I'm trying to write a function where I have a helper function, 'a -> bool. My problem is, when I'm trying to use the return value from this helper function, I get the error (because it is a function?)
The type 'a -> bool' does not support the 'equality' constraint,
Is there a way to get it to pre-evaluate the function so that I can use the return value?
Example:
let primelist n =
let rec prim n = function
| [] -> true
| x::xs when n % x = 0 -> false
| x::xs -> prim n xs
let rec help n list = function
| n when (prim n = true) -> List.rev (n::list)
| n -> List.rev list
| i when (prim i = true) -> help n (i::list) (i+1)
| i -> help n list (i+1)
help [2] n
Something like this would do the trick:
let primelist n =
let rec prim n = function
| [] -> true
| x::xs when n % x = 0 -> false
| x::xs -> prim n xs
let rec help n list arg =
let prime n = prim n list
match arg with
| n when (prime n = true) -> List.rev (n::list)
| n -> List.rev list
| i when (prime i = true) -> help n (i::list) (i+1)
| i -> help n list (i+1)
help [2] n
Here I have used currying to create a new function.
Related
I need some help with my hometask: to express one function (sort) through others (smallest, delete, insert). If you know how, please, tell me, how I can do running my recursion cicle? it doing now only one step. maybe something like this: val4 -> head :: tail |> sort tail on line 25 (val4)?
let rec smallest = function
| x :: y :: tail when x <= y -> smallest (x :: tail)
| x :: y :: tail when x > y -> smallest (y :: tail)
| [x] -> Some x
| _ -> None
let rec delete (n, xs) =
match (n, xs) with
| (n, x :: xs) when n <> x -> x :: delete (n, xs)
| (n, x :: xs) when n = x -> xs
| (n, _) -> []
let rec insert (xs, n) =
match (xs, n) with
| ([x], n) when x < n -> [x]#[n]
| (x :: xs, n) when x < n -> x :: insert (xs, n)
| (x :: xs, n) when x >= n -> n :: x :: xs
| (_, _) -> []
let rec sort = function
| xs -> let val1 = smallest xs
let val2 = val1.[0]
let val3 = delete (val2, xs)
let val4 = insert (val3, val2)
val4
let res = sort [5; 4; 3; 2; 1; 1]
printfn "%A" res
This is sort of like insertion sort, but since you're always finding the smallest number in the whole list instead of the next highest number, it will recurse forever unless you skip whatever you've already found to be the smallest.
Furthermore, your insert and delete functions act not on the item index, but on equality to the value, so it won't be able to handle repeated numbers.
Keeping most of your original code the same, usually you have an inner recursive function to help you keep track of state. This is a common FP pattern.
let sort lst =
let size = lst |> List.length
let rec sort' xs = function
| index when index = size -> xs
| index ->
let val1 = smallest (xs |> List.skip index)
let val2 = val1.[0]
let val3 = delete (val2, xs)
let val4 = insert (val3, val2)
sort' val4 (index + 1)
sort' lst 0
let res = sort [5; 3; 2; 4; 1; ]
printfn "%A" res
Needless to say, this isn't correct or performant, and each iteration traverses the list multiple times. It probably runs in cubic time.
But keep learning!
I found it... I only had changed 4 & 5 lines above in the "smallest" on this: | [x] -> Some x
| _ -> None, when there was: | [x] -> [x]
| _ -> []
let rec sort = function
| xs -> match xs with
| head :: tail -> let val1 = smallest xs
match val1 with
| Some x -> let val2 = delete (x, xs)
let val3 = insert (val2, x)
let val4 = (fun list -> match list with head :: tail -> head :: sort tail | _ -> [])
val4 val3
| None -> []
| _ -> []
// let res = sort [5; 4; 3; 2; 1]
// printfn "%A" res
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 need to check if a list starts with another, shorter list. The function, when using when guards is trivial:
let rec startsWith l1 l2 =
match l1, l2 with
| [], _ | _, [] -> true
| x::xs, y::ys when x = y -> startsWith xs ys
| _ -> false
let lst1 = [ 1; 2; 1 ]
let lst2 = [ 1; 2; 1; 2; 3; ]
let lst3 = [ 1; 3; 1; 2; 3; ]
let c1 = startsWith lst1 lst2 // true
let c2 = startsWith lst1 lst3 // false
But whatever I tried along the lines of an Active Pattern:
let (|HeadsMatch|) (l1 : ('a) list) (l2 : ('a) list) =
if l1.Head = l2.Head then Some(l1.Tail, l2.Tail) else None
let rec startsWith l1 l2 =
match l1, l2 with
| [], _ | _, [] -> true
| HeadsMatch /* need to capture the result */ -> startsWith t1 t2
| _ -> false
I could not make to compile. How to make a version of this function using Active pattern? And if this is not possible, can you explain why?
P.S. Any other nice ways to write the above function?
EDIT: I took the snippet from Daniel's answer to not distract from the real question.
EDIT: My problems started in the beginning. I have defined the active pattern function as
let (|HeadsMatch|_|) lst1 lst2 =
but it should have been
let (|HeadsMatch|_|) (lst1, lst2) =
In which case it would match as in the accepted answer.
I suppose the nicest way might be
let startsWith = Seq.forall2 (=)
If you want to write it from scratch, you need to match on both lists:
let rec startsWith l1 l2 =
match l1, l2 with
| [], _ | _, [] -> true
| x::xs, y::ys when x = y -> startsWith xs ys
| _ -> false
If you want to write it with an active pattern for learning purposes, using Tarmil's definition it would be
let rec startsWith l1 l2 =
match l1, l2 with
| [], _ | _, [] -> true
| HeadsMatch(xs, ys) -> startsWith xs ys
| _ -> false
There are two errors in the definition of your active pattern:
It's a partial active pattern (since it is possible that it doesn't match) so the syntax is (|HeadsMatch|_|).
You need to take the two lists as a pair, since you want to match lst1, lst2.
With these, the code will compile. But it will throw an exception at runtime, because you use .Head and .Tail on lists when you don't know if they have any element; you're not defining the behavior if one of the lists is empty.
Here is an idiomatic implementation of HeadsMatch:
let (|HeadsMatch|_|) (lst1, lst2) =
match (lst1, lst2) with
| (x :: xs, y :: ys) when x = y -> Some (xs, ys)
| _ -> None
Without guard:
let (|HeadsMatch|_|) (lst1, lst2) =
match (lst1, lst2) with
| (x :: xs, y :: ys) ->
if x = y then Some (xs, ys) else None
| _ -> None
As a side-note, your first implementation has the same problem. The following will throw a runtime exception:
startsWith [1;2] [1]
because you don't check that lst2 is not empty before using .Head and .Tail on it. In general, you should avoid these two methods almost all the time.
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'm positive that there is a better way to swap items in a list by pairs ( [1;2;3;4] -> [2;1;4;3] ) as I'm doing too many appends for my liking but I'm not sure how best to do it.
let swapItems lst =
let f acc item =
match acc with
| [] -> [item]
| hd :: next :: tl when tl <> [] -> [next] # tl # [item;hd]
| _ -> item :: acc
List.fold f [] lst
How can I improve this? This only works on lists that have an even length.
Simplest possible solution:
let rec swapItems = function
| a::b::xs -> b::a::swapItems xs
| xs -> xs
I like to make the names of variables that are sequences like lists "plural", e.g. xs instead of x.
Note that this is not tail recursive so it will stack overflow if you give it a very long list.
What about this:
let rec swapItems = function
| []
| _::[] as l -> l
| a::b::t ->
b::a::(swapItems t)
?
Using higher order functions this can be done as:
let swapItems l =
l |> List.toSeq |> Seq.pairwise
|> Seq.mapi (fun i (a,b) -> if i % 2 = 0 then seq [b;a] else Seq.empty)
|> Seq.concat |> Seq.toList