0

I am new to programming in functional languages. I am attempting to implement the F# collect for list.

let rec collect func list =
     match list with
     | [] -> []
     | hd::tl -> let tlResult = collect func tl 
                 func hd::tlResult;;

collect (fun x -> [for i in 1..3 -> x * i]) [1;2;3];;

should print:

val it : int list = [1; 2; 3; 2; 4; 6; 3; 6; 9]

but I got:

val it : int list = [[1; 2; 3;], [2; 4; 6;], [3; 6; 9]]
svick
  • 236,525
  • 50
  • 385
  • 514
Lawliet N
  • 5
  • 2

2 Answers2

3

Here's a tail recursive collect that won't stack overflow for large lists.

let collect f xs =
    let rec prepend res xs = function
        | [] -> loop res xs
        | y::ys -> prepend (y::res) xs ys
    and loop res = function
        | [] -> List.rev res
        | x::xs -> prepend res xs (f x)
    loop [] xs

A simpler version, that's somewhat cheating, is:

let collect (f: _ -> list<_>) (xs: list<_>) = [ for x in xs do yield! f x ]
Daniel
  • 47,404
  • 11
  • 101
  • 179
2

The collect function is tricky to implement efficiently in the functional style, but you can quite easily implement it using the @ operator that concatenates lists:

let rec collect f input =
  match input with
  | [] -> []
  | x::xs -> (f x) @ (collect f xs)  
Tomas Petricek
  • 240,744
  • 19
  • 378
  • 553