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)
Related
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 -> …
Hello I am new to OCaml And I am trying to learn the basic syntax of tail recursion. I wrote the following code in order to get a list and return the list with duples containing element and its index. for example
["b";"c";"dd";] -> [("b", 0); ("c", 1); ("dd", 2)]
I wrote the following code:
let enumerateWithTail lst =
let rec inside lst acc index =
match lst with
| [] -> acc
| x::xs -> inside xs (x,index)::acc (index+1)
in inside lst [] 0;;
This doesn't work but my professors example(which at least I think its pretty similar) works. My professors code is:
let enumerate lst =
let rec aux lst acc =
match lst with
| [] -> acc
| x::xs -> let (eList, index) = acc
in aux xs ((x, index)::eList, index+1)
in List.rev(fst(aux lst ([], 0)))
Can someone please explain why my code gives the error:
This expression has type 'a * 'b
but an expression was expected of type 'c list
Thanks in advance!
The problem is with precedence. Function application has higher precedence than any operator, including ::, so this:
inside xs (x,index)::acc (index+1)
is interpreted as:
(inside xs (x,index)) :: (acc (index+1))
whereas what you want is:
inside xs ((x,index)::acc) (index+1)
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.