If you already have an imperative version, you can follow many small steps to the rector for a recursive implementation .
Recursion
While I don't know what your imperative version looks like, here's a recursive version:
let pack xs = let rec imp acc = function | [] -> acc | h::t -> match acc with | [] -> imp [(h, 1)] t | (i, count) :: ta -> if h = i then imp ((i, count + 1) :: ta) t else imp ((h, 1) :: (i, count) :: ta) t xs |> imp [] |> List.rev
This function is of type 'a list -> ('a * int) list when 'a : equality . To do this, a private "implementation function" called imp . This function is recursive and overlays the drive (called acc ). This drive is a list of results of type ('a * int) list .
If the battery list is empty, the head of the original list ( h ), as well as counter 1 is created as a tuple as the only element of the updated battery, and the imp function is recursively called with this updated battery.
If the drive already contains at least one element, the element is extracted using pattern matching, and the element in this tuple ( i ) is compared with h . If h = i , the battery is updated; otherwise, the new tuple is considered acc . In both cases, however, imp recursively called with a new battery.
You can call it with a list equivalent to the original tuple, for example:
> pack [1; 2; 2; 3; 2; 2; 2; 4];; val it : (int * int) list = [(1, 1); (2, 2); (3, 1); (2, 3); (4, 1)]
Fold
Once you have a recursive version, you often have a recipe for a version that uses a fold. In this case, since the pack function above should cancel the drive at the end (using List.rev ), the correct fold is most suitable. In F #, this is done with the built-in List.foldBack function:
let pack' xs = let imp x = function | (i, count) :: ta when i = x -> (i, count + 1) :: ta | ta -> (x, 1) :: ta List.foldBack imp xs []
In this case, the function passed to List.foldBack is too complex to pass as an anonymous function, so I decided to define it as a private internal function. This is equivalent to the recursive imp function used by the above pack function, but you'll know that it doesn't need to call itself recursively. Instead, you just need to return the new value for the battery.
The result is the same:
> pack' [1; 2; 2; 3; 2; 2; 2; 4];; val it : (int * int) list = [(1, 1); (2, 2); (3, 1); (2, 3); (4, 1)]