How to fix pattern matching recursive call for tuples OCAML? - ocaml

I'm coding a helper function for encodeHelper but cannot seem to get the pattern matching to work in the recursive call. Does anyone know how to fix this error?
Please look at the code and error message in UTOP
let rec encodeHelper (l : 'a list) (curr : ('a * int) list) (currElement : ('a * int) option) =
match l, currElement with
| [], None -> curr
| [], Some(k) as currElement -> curr #[(fst k, snd k)]
| hd1::tl, None -> encodeHelper tl curr (k, 1)
| hd::tl, Some(k) ->
let element_ = fst k and
amount = snd k in
if element_ = hd
then encodeHelper tl curr (element_, amount+1)
else
encodeHelper tl (curr # [(element_, amount)]) (hd, 1)
The error message is that (k,1) in the recursive call on the 5th line is This expression has type 'b * 'c but an expression was expected of type ('a * int) option
Let me know if you have tips / ways to fix this!

The compiler is telling you that this expression is wrong:
encodeHelper tl curr (k, 1)
Indeed, the third argument of encodeHelper is specified to be of type ('a * int) option and the expression (k, 1) can't possiblly be of this type. An option type is None or Some x.
Possibly it will work better if you replace (k, 1) with (Some (k, 1)). However I don't see a definition of k in this branch of the match.

Related

OCaml Recursive function : sublist elements multiplied by their position in a list and then summed

I’m trying to create a function that takes an int list as an argument and returns the sum of the product between an int and its position in the list. To put in an example this : multSum [5; 11; 15] should return (5 * 1 + 11 * 2 + 15 * 3) = 72.
It should be written recursively and I’m trying while avoiding List.map or List.filter or any other prefabricated functions.
By dividing and reigning the query above, I have so far started by trying the following :
let rec tir f acc l =
match l with
|[] -> acc
|h::t -> tir f (f acc h) t ;;
val tir : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
then I moved to this :
let rec carto f a b =
match (a,b) with
|([],[])->([])
|(h1::t1,h2::t2)->(f h1 h2):: (carto f t1 t2)
|_->invalid_arg "carto";;
val carto : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list = <fun>
with the final idea to be able to do that :
let prod arg1 arg2 =
tir (+) 1 (carto ( * ) arg1 arg2);;
val prod : int list -> int list -> int = <fun>
But I am stuck now and I’m not sure of my orientation from here forward. I thought of trying to search for the index in a "l" and replace each index int in the acc, in order to make it work but I'm afraid I'm rather complicating things... Any help please ?
Edit 1 :
let rec multSum l =
let rec indices n xs = match xs with
| [] -> []
| h::t -> n::(indices (n+1) t)in
let rec tir f acc l =
match l with
|[] -> acc
|h::t -> tir f (f acc h) t in
let rec carto f a b =
match (a,b) with
|([],[])->([])
|(h1::t1,h2::t2)->(f h1 h2):: (carto f t1 t2)
|_->invalid_arg "carto" in
let prod arg1 arg2 =
tir (+) 0 (carto ( * ) arg1 arg2) in
prod l (indices 1 l);;
val multSum : int list -> int = <fun>
Building on your replies, surely these are 'fold' and 'map' rewritten. At least, I'm sure now that I was on the right track. I have come to put together the whole code as signaled above in Edit 1.
It seems to be working well... I know that I want a recursive function and here it is. But, do you think it could be done even shorter recursively of course?
#coredump is quite right about this looking like an ideal scenario for a fold, but the extra functions aren't really that necessary. We can just use a tuple to pass the index and sum information around, then when we're done, discard the index information from the tuple.
let sum_list_prod lst =
let (_, result) = List.fold_left
(fun (i, sum) x -> (i + 1, sum + i * x))
(1, 0)
lst
in
result
Edit: A simple implementation of a left fold to demonstrate the recursion going on here.
let rec foldl f init lst =
match lst with
| [] -> init
| first :: rest -> foldl f (f init first) rest
So working through a simple example with sum_list_prod:
sum_list_prod [2; 3; 4]
Calls the fold like so:
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (1, 0) [2; 3; 4]
And as that evaluates:
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (1, 0) [2; 3; 4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (2, 2) [3; 4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (3, 8) [4]
List.fold_left (fun (i, sum) x -> (i + 1, sum + i * x)) (4, 20) []
(4, 20)
And then we throw away the 4 because we don't need it anymore and are just left with 20.
Your tir functions looks like a fold; in fact has the exact same type as List.fold_left:
# List.fold_left;;
- : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
In the following snippets the prod function looks like a map2
# List.map2;;
- : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list = <fun>
You can use a fold and a map to compute the function you want, but you also need first to build a list of indices from the list of values. You could do this as follows:
let rec indices n xs = match xs with
| [] -> []
| h::t -> n::(indices (n+1) t);;
For example:
# indices 1 [5;1;3];;
- : int list = [1; 2; 3]
This is not recursive terminal, if you first computed the length of the list, how would you build the list in a recursive terminal way?
Then you should be able to call prod on a list xs and on a secondary list indices 1 xs. It is a bit wasteful because you need to build an auxiliary list, but it looks quite simple to me to understand, higher-order functions like map or fold do work on whole lists so there are fewer corner cases to consider.
But, it might be better to first write a direct recursive function for your particular problem before going the more abstract route.
The direct recursive function also requires no additional memory allocation. If you write a recursive terminal function you'll carry additional accumulator values:
the current position in the list, initially 1
the current sum of products, initially 0
Then, your function has the following skeleton:
let rec f xs index product = match xs with
| [] -> ...
| h::t -> ...
You can wrap it in a main function g:
let g xs = f xs 1 0;;

List.assoc using List.find

I want to implement the List.assoc function using List.find, this is what I have tried:
let rec assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> try (List.find (fun x -> a = x) lista)
b
with Not_found -> assoc l x;;
but it gives me this error:
This expression has type ('a * 'b) list but an expression was expected of type 'a list
The type variable 'a occurs inside 'a * 'b
I don't know if this is something expected to happen or if I'm doing something wrong. I also tried this as an alternative:
let assoc lista x = match lista with
| [] -> raise Not_found
| (a,b)::l -> match List.split lista with
| (l1,l2) -> let ind = find l1 (List.find (fun s -> compare a x = 0))
in List.nth l2 ind;;
where find is a function that returns the index of the element requested:
let rec find lst x =
match lst with
| [] -> raise Not_found
| h :: t -> if x = h then 0 else 1 + find t x;;
with this code the problem is that the function should have type ('a * 'b) list -> 'a -> 'b, but instead it's (('a list -> 'a) * 'b) list -> ('a list -> 'a) -> 'b, so when I try
assoc [(1,a);(2,b);(3,c)] 2;;
I get:
This expression has type int but an expression was expected of type
'a list -> 'a (refering to the first element of the pair inside the list)
I don't understand why I don't get the expected function type.
First off, a quick suggestion on making your assoc function more idiomatic OCaml: have it take the list as the last argument.
Secondly, why are you attempting to implement this in terms of find? It's much easier without.
let rec assoc x lista =
match lista with
| [] -> raise Not_found
| (a, b) :: xs -> if a = x then b else assoc x xs
Something like this is simpler and substantially more efficient with the way lists work in OCaml.
Having the list as the last argument, even means we can write this more tersely.
let rec assoc x =
function
| [] -> raise Not_found
| (a, b) :: xs -> if a = x then b else assoc x xs
As to your question, OCaml infers the types of functions from how they're used.
find l1 (List.find (fun s -> compare a x = 0))
We know l1 is an int list. So we must be trying to find it in an int list list. So:
List.find (fun s -> compare a x = 0)
Must return an int list list. It's a mess. Try rethinking your function and you'll end up with something much easier to reason about.

weird errors when compiling under corebuild

I really don't understand what's going on. I have the following code:
let rec interleave n l =
match l with
[] -> [[n]]
| head::tail -> (n::l)::(List.map (~f:fun y -> head::y) (interleave n tail))
in let rec aux l =
match l with
[] -> [l]
| head::tail -> List.concat ( List.map (interleave head) (aux tail) )
When compiling with ocaml it compiles and works as expected but under corebuild it gives me the following error:
The expression has type 'a list -> `a list list but an expression was
expected of type 'b list
Does it have something to do with labels again (as you see from ~f:fun y -> ... it has already annoyed me before)? If yes what kind of label should I use and where?
You need to reread part of manual about labeled arguments.
let rec interleave n l =
match l with
| [] -> [[n]]
| head::tail -> (n::l)::(List.map ~f:(fun y -> head::y) (interleave n tail))
and aux l =
match l with
| [] -> [l]
| head::tail -> List.concat ( List.map ~f:(interleave head) (aux tail) );;
N.B. right syntax for labeled arguments is ~label:expression
N.B. In Core List.map function has type 'a list -> f:('a -> 'b) -> 'b list and if you forget to add label to your function f it will try to unify 2nd argument with a function. That's why you have so weird error message.

Ocaml - parameter type when checking for duplicates in a list

I've got a basic function which checks a list for duplicates and returns true if they are found, false otherwise.
# let rec check_dup l = match l with
[] -> false
| (h::t) ->
let x = (List.filter h t) in
if (x == []) then
check_dup t
else
true
;;
Yet when I try to use this code I get the error
Characters 92-93:
let x = (List.filter h t) in
^
Error: This expression has type ('a -> bool) list
but an expression was expected of type 'a list
I don't really understand why this is happening, where is the a->bool list type coming from?
The type ('a -> bool) list is coming from the type of filter and from the pattern match h::t in combination. You're asking to use a single element of the list, h, as a predicate to be applied to every element of the list t. The ML type system cannot express this situation. filter expects two arguments, one of some type 'a -> bool where 'a is unknown, and a second argument of type 'a list, where 'a is the same unknown type as in the first argument. So h must have type 'a -> bool and t must have type 'a list.
But you have also written h::t, which means that there is another unknown type 'b such that h has type 'b and t has type 'b list. Put this together and you get this set of equations:
'a -> bool == 'b
'a list == 'b list
The type checker looks at this and decides maybe 'a == 'b, yielding the simpler problem
'a -> bool == 'a
and it can't find any solution, so it bleats.
Neither the simpler form nor the original equation has a solution.
You are probably looking for List.filter (fun x -> x = h) t, and you would probably be even better off using List.exists.
For complete this answer I post the final function for search duplicate value in array:
let lstOne = [1;5;4;3;10;9;5;5;4];;
let lstTwo = [1;5;4;3;10];;
let rec check_dup l = match l with
[] -> false
| (h::t) ->
let x = (List.filter (fun x -> x = h) t) in
if (x == []) then
check_dup t
else
true;;
and when the function run:
# check_dup lstOne
- : bool = true
# check_dup lstTwo
- : bool = false
#

Optional argument cannot be erased?

I wanted to have a tail-recursive version of List.map, so I wrote my own. Here it is:
let rec list_map f l ?(accum=[])=
match l with
head :: tail -> list_map f tail ~accum:(head :: accum)
| [] -> accum;;
Whenever I compile this function, I get:
File "main.ml", line 69, characters 29-31:
Warning X: this optional argument cannot be erased.
The tutorial says that this means that I'm trying to create a function with no non-optional arguments. But the function above clearly takes non-optional arguments.
I'm probably just doing something really dumb, but what?
Yeah your non-optional argument can't be last, because since OCaml supports partial applications, a function missing a last optional argument will just look like a partially-applied function which is still looking for the optional argument. The only way for it to tell that you don't intend to provide the optional argument is that it sees that you have provided an argument after it.
If you have to have it last, you can put a dummy unit argument after it:
let rec list_map f l ?(accum=[]) () =
match l with
head :: tail -> list_map f tail ~accum:(head :: accum) ()
| [] -> accum;;
But in this case yeah changing the order would be better.
You need a non-optional argument after the optional one.
Just change the order of the arguments of your function:
let rec list_map f ?(accum=[]) l=
match l with
head :: tail -> list_map f ~accum:(head :: accum) tail
| [] -> accum;;
The previous solutions do compile, but won't give the expected result. The function f is never applied to the arguments. A correct code is:
let rec list_map f ?(accum = []) l = match l with
| head :: tail -> list_map f ~accum:(f head :: accum) tail
| [] -> accum;;
The inferred type is:
val list_map : ('a -> 'b) -> ?accum:'b list -> 'a list -> 'b list = <fun>
... in contrast to the wrong one:
val list_map : 'a -> ?accum:'b list -> 'b list -> 'b list = <fun>
Please note, that the result list is reversed:
# list_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [16.; 8.; 4.; 2.]
... and equals the function rev_list from the List module:
# List.rev_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [16.; 8.; 4.; 2.]
So you may want to change your function into:
let rec list_map f ?(accum = []) l = match l with
| head :: tail -> list_map f ~accum:(f head :: accum) tail
| [] -> List.rev accum;;
... which should be tail-recursive as well (according to the manual) and returns the list in the original order:
# list_map ( ( ** ) 2.) [1.;2.;3.;4.];;
- : float list = [2.; 4.; 8.; 16.]