Merge two lists
One important point is that the function is not correct. It fails with the input ([1;2;3], [])
since you missed the case of (xs, [])
in pattern matching. Moreover, arguments are better in the curried form in order that it's easier to use with partial application. Here is the corrected version:
let rec interleave xs ys =
match xs, ys with
| [], ys -> ys
| xs, [] -> xs
| x::xs', y::ys' -> x::y::interleave xs' ys'
You can see that the function is not tail-recursive since it applies cons (::)
constructor twice after the recursive call returned. One interesting way to make it tail-recursive is using sequence expression:
let interleave xs ys =
let rec loop xs ys =
seq {
match xs, ys with
| [], ys -> yield! ys
| xs, [] -> yield! xs
| x::xs', y::ys' ->
yield x
yield y
yield! loop xs' ys'
}
loop xs ys |> List.ofSeq
Your function is almost right. let f = function
is shorthand for let f x = match x with
so you don't need explicit args. Also, your algorithm needs some tweaking.
let rec interleave = function //same as: let rec interleave (xs, ys) = match xs, ys with
|([], ys) -> ys
|(xs, []) -> xs
|(x::xs, y::ys) -> x :: y :: interleave (xs,ys)
interleave ([5;3;8],[2;9;4]) //output: [5; 2; 3; 9; 8; 4]
You can use this opportunity to define a more general higher order function - zipWith
, and then implement interleave
using it.
let rec zipWith f xlist ylist =
match f, xlist, ylist with
| f, (x :: xs), (y :: ys) -> f x y :: zipWith f xs ys
| _, _, _ -> []
let interleave xs ys = zipWith (fun a b -> [a; b]) xs ys |> List.concat
Edit:
As @pad said below, F# already has zipWith
under the nameList.map2
. So you can rewrite interleave
as follows:
let interleave xs ys = List.map2 (fun a b -> [a; b]) xs ys |> List.concat