weird errors when compiling under corebuild - ocaml

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.

Related

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.

Ocaml Type error: This expression has type 'a * 'b but an expression was expected of type 'c list

I'm required to output a pair of lists and I'm not understanding why the pair I'm returning is not of the correct type.
let rec split l = match l with
| [] -> []
| [y] -> [y]
| x :: xs ->
let rec helper l1 acc = match l1 with
| [] -> []
| x :: xs ->
if ((List.length xs) = ((List.length l) / 2)) then
(xs, (x :: acc))
else helper xs (x :: acc)
in helper l []
(Please take the time to copy/paste and format your code on SO rather than providing a link to an image. It makes it much easier to help, and more useful in the future.)
The first case of the match in your helper function doesn't return a pair. All the cases of a match need to return the same type (of course).
Note that the cases of your outermost match are also of different types (if you assume that helper returns a pair).

OCaml code consecutive list creation simple code

I have been trying one of the problems on 99 OCaml problems where you have to a have a list of all consecutive numbers in a list such as [2;3;4;4;5;6;6;6] -> [[2];[3];[4;4];[5];[6;6;6]]
let rec tail = function
| [] -> []
| [x] -> [x]
| x::xs -> tail xs;;
let pack lst =
let rec aux current acc = function
| [] -> current
| [x] -> if (tail acc) = x then (x::acc)::current
else [x]::current
| x::y::xs -> if (x=y) then aux current (x::acc) (y::xs)
else aux (acc::current) [] (y::xs)
in
aux [] [] lst;;
When i run this i get the error
Error: This expression has type 'a list
but an expression was expected of type 'a list list
The type variable 'a occurs inside 'a list
I was wondering what the problem is?
As Bergi pointed out (tail acc)=x is the problem. tail returns 'a list so x must also be of type 'a list. The following x::acc then infers that acc must be of type 'a list list. But tail acc infers acc as 'a list.
At this point OCaml can't unify the types of 'a list list and 'a list and gives the error you see.

last element in list using ocaml List.fold_left

I can find the last element of a list by the following code.
let last (xs:'a list) : 'a =
let rec aux xs prev =
match xs with
| [] -> prev
| x::ys -> aux ys x in
match xs with
| [] -> failwith "no element"
| x::xs -> aux xs x
How do I find the last element of the same list using the List.fold_left function in OCaml?
Thanks in advance!
fold_left accesses the list from the head to the tail, thus the function passed to fold_left should just replace the accumulator with the current element of the list. Thus simply,
let last = function
| x::xs -> List.fold_left (fun _ y -> y) x xs
| [] -> failwith "no element"
You can write your function directly, without the aux function.
let rec last = function
| x::[] -> x
| _::xs -> last xs
| [] -> failwith "no element"

How can I skip a term with List.Map in OCAML?

Suppose I have some code like this:
List.map (fun e -> if (e <> 1) then e + 1 else (*add nothing to the list*))
Is there a way to do this? If so, how?
I want to both manipulate the item if it matches some criteria and ignore it if it does not. Thus List.filter wouldn't seem to be the solution.
SML has a function mapPartial which does exactly this. Sadly this function does not exist in OCaml. However you can easily define it yourself like this:
let map_partial f xs =
let prepend_option x xs = match x with
| None -> xs
| Some x -> x :: xs in
List.rev (List.fold_left (fun acc x -> prepend_option (f x) acc) [] xs)
Usage:
map_partial (fun x -> if x <> 1 then Some (x+1) else None) [0;1;2;3]
will return [1;3;4].
Or you can use filter_map from extlib as ygrek pointed out.
Both Batteries and Extlib provide an equivalent of mapPartial: their extended List module sprovide a filter_map function of the type ('a -> 'b option) -> 'a list -> 'b list, allowing the map function to select items as well.
Another solution would be to use directly a foldl :
let f e l = if (e <> 1)
then (e + 1)::l
else l
in List.fold_left f [] list
But my preference is filter_map as Michael Ekstrand provided
Alternatively you can filter your list then apply the map on the resulted list as follows :
let map_bis predicate map_function lst =
List.map map_function (List.filter predicate lst);;
# val map_bis : ('a -> bool) -> ('a -> 'b) -> 'a list -> 'b list = <fun>
Usage :
# map_bis (fun e -> e<>1) (fun e -> e+1) [0;1;2;3];;
- : int list = [1; 3; 4]
You can also map values to singleton lists if you want to keep them or empty lists if you don't, and then concat the results.
List.concat (List.map (fun e -> if (e <> 1) then [e + 1] else []) my_list)
use
let rec process = function
| 1 :: t -> process t
| h :: t -> (h + 1) :: (process t)
| [] -> []
or tail recursive
let process =
let rec f acc = function
| 1 :: t -> f acc t
| h :: t -> f ((h + 1) :: acc) t
| [] -> List.rev acc in
f []
or with a composition of standard functions
let process l =
l |> List.filter ((<>)1)
|> List.map ((+)1)
The OCaml standard library has had List.filter_map since 4.08. This can therefore now be written as:
List.filter_map (fun e -> if e <> 1 then Some (e + 1) else None)