I have this function in haskell which I would like to code in F# using native syntax and not the array functions such as map2.
Haskell:
merge [] ys = ys
merge (x:xs) ys = x:merge ys xs
This code merges two lists index-wise like this:
INPUT: [1,2,3,4,5] [11,12,13,14]
OUTPUT: [1,11,2,12,3,13,4,14,5]
I tried doing it in F# and got this but it of course doesn't compile:
let rec mux x y = function
| [] -> []
| x::xs y::ys -> x::y::mux(xs,ys)
I am really struggling to work with two arrays in the pattern matching, thanks for any help you can give.
The Haskell function doesn't actually match on the two parameters. It only matches on the first parameter and takes the second parameter as is.
In F#, you can match on the first argument, and return a function that processes the second argument:
let rec mux = function
| [] -> (function ys -> ys)
| x::xt -> (function ys -> x :: mux ys xt)
But I find it clearer (and I think it's more efficient — at least it is in OCaml) to take in all the arguments at once, then analyze the argument you need to discriminate on:
let rec mux xs ys =
match xs with
| [] -> ys
| x::xt -> x :: mux ys xt
If you wanted to match on both variables, there would be several solutions. You could nest function constructs:
let rec mux = function
| [] -> (function [] -> … | y::yt -> …)
| x::xt -> (function [] -> … | y::yt -> …)
But here again I prefer nesting match constructs:
let rec mux xs ys =
match xs with
| [] -> (match ys with
| [] -> …
| y::yt -> …)
| x::xt -> (match ys with
| [] -> …
| y::yt -> …)
Alternatively, it's often nicer to match on the pair of inputs; it depends how coupled the two inputs are.
let rec mux xs ys =
match xs, ys with
| [], [] -> …
| [], y::yt -> …
| x::xt, [] -> …
| x::xt, y::yt -> …
Related
let rec merge = function
| ([], ys) -> ys
| (xs, []) -> xs
| (x::xs, y::ys) -> if x < y then x :: merge (xs, y::ys)
else y :: merge (x::xs, ys)
let rec split = function
| [] -> ([], [])
| [a] -> ([a], [])
| a::b::cs -> let (M,N) = split cs
(a::M, b::N)
let rec mergesort = function
| [] -> []
| L -> let (M, N) = split L
merge (mergesort M, mergesort N)
mergesort [5;3;2;1] // Will throw an error.
I took this code from here StackOverflow Question but when I run the mergesort with a list I get an error:
stdin(192,1): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : '_a list when '_a : comparison
How would I fix this problem? What is the problem? The more information, the better (so I can learn :) )
Your mergesort function is missing a case causing the signature to be inferred by the compiler to be 'a list -> 'b list instead of 'a list -> 'a list which it should be. The reason it should be 'a list -> 'a list is that you're not looking to changing the type of the list in mergesort.
Try changing your mergesort function to this, that should fix the problem:
let rec mergesort = function
| [] -> []
| [a] -> [a]
| L -> let (M, N) = split L
merge (mergesort M, mergesort N)
Another problem with your code however is that neither merge nor split is tail recursive and you will therefore get stack overflow exceptions on large lists (try to call the corrected mergesort like this mergesort [for i in 1000000..-1..1 -> i]).
You can make your split and merge functions tail recursive by using the accumulator pattern
let split list =
let rec aux l acc1 acc2 =
match l with
| [] -> (acc1,acc2)
| [x] -> (x::acc1,acc2)
| x::y::tail ->
aux tail (x::acc1) (y::acc2)
aux list [] []
let merge l1 l2 =
let rec aux l1 l2 result =
match l1, l2 with
| [], [] -> result
| [], h :: t | h :: t, [] -> aux [] t (h :: result)
| h1 :: t1, h2 :: t2 ->
if h1 < h2 then aux t1 l2 (h1 :: result)
else aux l1 t2 (h2 :: result)
List.rev (aux l1 l2 [])
You can read more about the accumulator pattern here; the examples are in lisp but it's a general pattern that works in any language that provides tail call optimization.
I can't figure out how to implement the Zip function in F#. Can anyone tell me what I am doing wrong? Here is what I have typed into fsi.exe:
> let rec zip xs ys =
- match xs with
- | [] -> []
- | head :: tail -> (match ys with
- | [] -> []
- | headY :: tailY -> (head, headY) :: zip tail tailY);;
val zip : xs:'a list -> ys:'b list -> ('a * 'b) list
> zip [1;2;3;4] ["a","b","c","d"];;
val it : (int * (string * string * string * string)) list =
[(1, ("a", "b", "c", "d"))]
In your example ["a","b","c","d"] is a list that contains one element which is 4-dimensional tuple. That is why you are getting unexpected results from zip.
Just use ; as elements delimiter instead.
I think it's worth pointing out that it's probably worth making the zip function tail-recursive as well in order to avoid stack overflows on larger lists.
Something like this perhaps
let zip3 xs ys =
let rec loop r xs ys =
match xs,ys with
| [],[] -> r
| xh::xt,yh::yt -> loop ((xh,yh)::r) xt yt
| _ -> failwith "xs & ys has different length"
loop [] xs ys |> List.rev
let rec merge = function
| ([], ys) -> ys
| (xs, []) -> xs
| (x::xs, y::ys) -> if x < y then x :: merge (xs, y::ys)
else y :: merge (x::xs, ys)
let rec split = function
| [] -> ([], [])
| [a] -> ([a], [])
| a::b::cs -> let (M,N) = split cs
(a::M, b::N)
let rec mergesort = function
| [] -> []
| L -> let (M, N) = split L
merge (mergesort M, mergesort N)
mergesort [5;3;2;1] // Will throw an error.
I took this code from here StackOverflow Question but when I run the mergesort with a list I get an error:
stdin(192,1): error FS0030: Value restriction. The value 'it' has been inferred to have generic type
val it : '_a list when '_a : comparison
How would I fix this problem? What is the problem? The more information, the better (so I can learn :) )
Your mergesort function is missing a case causing the signature to be inferred by the compiler to be 'a list -> 'b list instead of 'a list -> 'a list which it should be. The reason it should be 'a list -> 'a list is that you're not looking to changing the type of the list in mergesort.
Try changing your mergesort function to this, that should fix the problem:
let rec mergesort = function
| [] -> []
| [a] -> [a]
| L -> let (M, N) = split L
merge (mergesort M, mergesort N)
Another problem with your code however is that neither merge nor split is tail recursive and you will therefore get stack overflow exceptions on large lists (try to call the corrected mergesort like this mergesort [for i in 1000000..-1..1 -> i]).
You can make your split and merge functions tail recursive by using the accumulator pattern
let split list =
let rec aux l acc1 acc2 =
match l with
| [] -> (acc1,acc2)
| [x] -> (x::acc1,acc2)
| x::y::tail ->
aux tail (x::acc1) (y::acc2)
aux list [] []
let merge l1 l2 =
let rec aux l1 l2 result =
match l1, l2 with
| [], [] -> result
| [], h :: t | h :: t, [] -> aux [] t (h :: result)
| h1 :: t1, h2 :: t2 ->
if h1 < h2 then aux t1 l2 (h1 :: result)
else aux l1 t2 (h2 :: result)
List.rev (aux l1 l2 [])
You can read more about the accumulator pattern here; the examples are in lisp but it's a general pattern that works in any language that provides tail call optimization.
I have a very simple MergeSort implementation on List.
/// Divide the list into (almost) equal halves
let rec split = function
| [] -> [], []
| [x] -> [x], []
| x1::x2::xs -> let xs1, xs2 = split xs
x1::xs1, x2::xs2
/// Merge two sorted lists
let rec merge xs ys =
match xs, ys with
| [], _ -> ys
| _, [] -> xs
| x::xs', y::ys' when x <= y -> x::merge xs' ys
| _, y::ys' -> y::merge xs ys'
let rec mergeSort = function
| [] -> []
| xs -> let xs1, xs2 = split xs
merge (mergeSort xs1) (mergeSort xs2)
But whenever I tried to test with any input in F# Interactive:
let xs = mergeSort [1;4;3;2];;
I encountered a value restriction error:
error FS0030: Value restriction. The value 'xs' has been inferred to
have generic type
val xs : '_a list when '_a : comparison Either define 'xs' as a simple data term, make it a function with explicit arguments or, if
you do not intend for it to be generic, add a type annotation.
Why does it happen? What is a simple way to fix it?
You are not handling the special case of 1-element lists in mergeSort.
The general case is "too general" to infer the right type. As a consequence, the compiler infers a too generic type for the function ('a list -> 'b list) and the result is always a generic list (which is not allowed due to value restriction).
If you fix it like this, the type will be correctly inferred as 'a list -> 'a list.
let rec mergeSort = function
| [] -> []
| [x] -> [x]
| xs -> let xs1, xs2 = split xs
merge (mergeSort xs1) (mergeSort xs2)
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
F# - cross product of two lists
Projecting a list of lists efficiently in F#
I have a function that takes two integer lists and returns a single list with all the cartesian products. I think i have the correct idea but not the right implementation. Can I get some pointers?
let rec cartesian = function
| ([],[]) -> []
| (xs,[]) -> []
| ([],ys) -> []
| (x::xs,ys) -> List.map(fun y -> (x,y)::[]) cartesian (xs,ys)
This is a quick fix:
let rec cartesian = function
| ([],[]) -> []
| (xs,[]) -> []
| ([],ys) -> []
| (x::xs, ys) -> (List.map(fun y -> x,y) ys) # (cartesian (xs,ys))
The idea is that with each element x, you generate a list [(x, y1); (x, y2); ...; (x, yn)] and concatenate those lists altogether.
In your function, the first pattern matching case is redundant. And the arguments are more convenient to be in the curried form. The function could look like this:
let rec cartesian xs ys =
match xs, ys with
| _, [] -> []
| [], _ -> []
| x::xs', _ -> (List.map (fun y -> x, y) ys) # (cartesian xs' ys)
Once you understand the idea, you can see that the high-order function List.collect perfectly matches the task:
let cartesian xs ys =
xs |> List.collect (fun x -> ys |> List.map (fun y -> x, y))