Implementing zip in OCaml - ocaml

I have haskell background, now trying to learn OCaml.
I'm trying to implement zip as an exercise, but I'm getting a syntax error; what's the correct syntax?
let rec zip (l1 : 'a list) (l2 : 'b list) : ('a * 'b) list =
match l1 l2 with
[] _ -> []
| _ [] -> []
| (x::xs) (y::ys) -> (x,y)::(zip xs ys)

When you deconstruct/construct a pair, you need to put a , between its members.
Which means your zip function becomes:
let rec zip (l1 : 'a list) (l2 : 'b list) : ('a * 'b) list =
match l1,l2 with
| [],_ -> []
| _,[] -> []
| (x::xs),(y::ys) -> (x,y)::(zip xs ys)
Also, note that OCaml provide or-patterns when several cases of the pattern matching return the same value

This is not a pattern:
_ []
There is no pattern that consists of a function application. This makes it a syntax error and not just a semantic problem as in the previous expression l1 l2.
(Edited to give an actually erroneous pattern.)

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 complexity of List.assoc

In the List module of OCaml, how is : val assoc : 'a -> ('a * 'b) list -> 'b implemented and (therefore) what is the complexity of this operation ? Is there a hashtbl hidden behind the scenes ?
The code is available online here: https://github.com/ocaml/ocaml/blob/trunk/stdlib/list.ml#L180-L182
let rec assoc x = function
[] -> raise Not_found
| (a,b)::l -> if compare a x = 0 then b else assoc x l
As you can see it's implemented as a linear search over the list.

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.

Function to flatten `('a list * b' list) list` to `'a list* 'b list` in OCaml

I need a function in OCaml that will take a type of
('a list * b' list) list and make of it
'a list * b' list. I have tried with the built in functions List.flatten and List.concat but they do not work, they require a type of 'c list list. Can someone help me?
You have to use the functions List.split and List.flatten:
let my_function l =
let (fst_list, snd_list) = List.split l in
List.flatten fst_list, List.flatten snd_list ;;
First the split function will generate and 'a list list and a 'b list list, then you just have to flatten them.
You can do it using the function fold_left like this :
You start with two empty lists working as accumulators. For every sub-lists in your the input list, you add the elements into the respective accumulator (elements of the first sub-list in the first accumulator and same thing for the second sub-list).
# let flatten l =
let (l1,l2) =
List.fold_left (fun (l1,l2) (x,y) ->
(x :: l1, y :: l2)) ([], []) l in
List.rev (List.flatten l1), List.rev (List.flatten l2);;
val flatten : ('a list * 'b list) list -> 'a list * 'b list = <fun>
#
Unfortunately there is no map for tuples and you need to decompose - e.g. using using split and flatten:
let splcat x = match List.split x with | (a,b) -> (List.flatten a, List.flatten b) ;;
That's how it looks on the commandline:
utop # splcat [([1;2],["a"]); ([3],["uvw";"xyz"]) ] ;;
- : int list * bytes list = ([1; 2; 3], ["a"; "uvw"; "xyz"])
The following should work:
let split2 l = (List.map fst l, List.map snd l)
let flatten2' (l1, l2) = (List.flatten l1, List.flatten l2)
let flatten2 l = flatten2' (split2 l)
Here, split2 will turn a ('a list * 'b list) list into a ('a list list * 'b list list) (fst and snd return the first and second component of a pair, respectively) and flatten2' will individually flatten the two components. And flatten2 will finally do what you require. You can also pack this into a single function, but I think this is easier to understand.
Note that neither List.map nor List.flatten is tail-recursive; if you need tail-recursive versions, there are other libraries that have them, or you can build them from the standard library using rev_xxx functions or write them from scratch.

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.