Let OCaml function work with lists and ints - ocaml

How can I make this function can fit with List and Int?
type 'a tree =
| Leaf
| Node of 'a tree * 'a * 'a tree;;
let rec fold_inorder f acc t =
match t with
| Leaf -> acc
| Node (l, x, r) ->
let ar = fold_inorder f acc r in
let an = x :: ar in
fold_inorder f an l;;
I am trying to
fold_inorder (fun acc x -> acc + x) 0 (Node (Node (Leaf,1,Leaf), 2, Node (Leaf,3,Leaf)));;
But give me error:
Error: This expression has type int but an expression was expected of type
'a list

You've restricted your accumulator type to being a list. In your recursion, you write
let an = x :: ar in
fold_inorder f an l;;
an is clearly a list (it was constructed using the :: list constructor), and it's being passed as the second argument to fold_inorder. Hence, fold_inorder can only accept lists as the second argument. On the other hand, when you call fold_inorder at the bottom, you pass 0 as the second argument, which is an integer and not a list, hence the error.
Rather than using :: to build an (the middle accumulator), you should use your supplied f function, which was given in order to combine values.
let an = f ar x in

Related

length function without recursion ocaml

I'm trying to rewrite the List.length function without using recursion. Here's my code:
(* given *)
type 'a list =
| []
| (::) of 'a * 'a list
let nil : 'a list = []
let cons (hd : 'a) (tl : 'a list): 'a list = hd :: tl
let length (ls : 'a list): int =
let i = fold_left(fun x y -> Fun.const 1 :: y) [] ls in
fold_left(fun x y -> x + y) 0 i
OCaml gave me an error on the last line fold_left(fun x y -> x + y) 0 i and saying my i here has type ('a -> int) list but an expression was expected of type int list, is there any way I can fix this? Thank you!
It's not entirely clear to me what you are trying to achieve with Fun.const, but you can actually achieve length with a single fold_left:
let length l =
fold_left (fun acc _ -> acc+1) 0 l
There are a few issues with your attempt.
As Fun.const creates in this case a function which always returns 1, and your expression parses as: (Fun.const 1) :: y your first use of List.fold_left is generating a list of functions which all return one. But there are not the value 1.
Thus when you use fold_left (fun x y -> x + y) 0 i you are trying to add a function to an int. Clearly this doesn't work. You need to apply some argument to that function.
let length (ls : 'a list): int =
let i = List.fold_left(fun x y -> Fun.const 1 :: y) [] ls in
List.fold_left(fun x y -> x + y ()) 0 i
This compiles. But... the type doesn't look quite right.
val length : (unit -> int) list list -> int = <fun>
This results from having the argument order to the function List.fold_left takes wrong. The first argument is the initial value. The second is the first element from the list.
If we change that:
let length (ls : 'a list): int =
let i = List.fold_left(fun y _ -> Fun.const 1 :: y) [] ls in
List.fold_left(fun x y -> x + y ()) 0 i
The type of this function is:
val length : 'a list -> int = <fun>
But as Blackbeans has noted, there is a much simpler way to write this using a single call to List.fold_left.

Ocaml : flatten a list if necessary

I start in ocaml and I would like to know how in a recursive function of type
'a list -> int ,
let rec int l =
match l with
| [] -> 0
| hd::tl -> 10
the list can be flattened only if necessary
for example if [0;2;3;4] just returns the int
and if [[0];2; [3;4]], then do -> [0;2;3;4] and then return the int.
Thank you in advance.
You cannot store directly either a list or a number in a list, because lists must store values of the same type.
You can, however, declare a variant type (tagged union) for both kinds of values.
Here the type 'a lisr_or_val represents values that are either a value of type 'a, denoted for example (A 3), or lists of values of type 'a lisr_or_val, for example (L [(A 3); (A 5)]):
type 'a list_or_val =
L of 'a list_or_val list
| A of 'a
Then you access the leftmost value as follows:
let rec leftmost_value term = match term with
| L ([]) -> failwith "Unexpected"
| L (x::_) -> leftmost_value x
| A v -> v;;
For example:
# leftmost_value (L [A 5; A 3]);;
- : int = 5

Unknown Type Error in OCaml

I'm attempting to create a new list of all the unique items from another list. My in_list function works properly and returns a value saying whether or not the value is found in the seen_list, but I can't for the life of me get this to compile.
let uniq x = match in_list x seen_list with
| true -> seen_list
| false -> seen_list#[x]
| _ -> seen_list
;;
List.iter uniq check_list;;
The problem is some sort of type error. Here it is:
Error: This expression has type int -> int list
but an expression was expected of type int -> unit
Type int list is not compatible with type unit
In essence you want to take the result returned by uniq and pass it as the list for the next call of uniq. To do this, you need to use a fold, or write your own recursion. The purpose of List.iter is just to call an imperative function for each element of a list. It doesn't combine the answers in any way. That's why you're getting a type error—your function isn't imperative. I.e., it doesn't return unit.
Perhaps this is what you want:
let rec uniq_list lst =
match lst with
| [] -> []
| x :: xs ->
let r = uniq_list xs in
if in_list x r then r else x :: r
Or, using List.fold_right (equivalent to the recursive function above):
let uniq_list lst =
List.fold_right
(fun x r -> if in_list x r then r else x :: r)
lst
[]
Or using List.fold_left which is tail-recursive:
let uniq_list lst =
List.fold_left
(fun r x -> if in_list x r then r else x :: r)
[]
lst
By the way, your in_list is equivalent to the standard library function List.mem.

OCaml error filter list using higher order functions

So I have this exercise:
filter (fun x -> x = 0) [(1,0);(2,1);(3,0);(4,1)];;
result int list [1;3]
So basically you have to match your x in fun with the second number in list and if its the same you create new list with the first number.
My solution but is wrong
let rec filter f = function
| []->[]
| x::l -> if f=snd x then fst x :: filter f l else [];;
I get the following error when i want to try the code:
Error: This expression has type int but an expression was expected of
type
int -> bool
I can't reproduce the problem you report. Here's what I see when I try your code:
$ ocaml
OCaml version 4.02.1
# let rec filter f = function
| []->[]
| x::l -> if f=snd x then fst x :: filter f l else [] ;;
val filter : 'a -> ('b * 'a) list -> 'b list = <fun>
# filter 0 [(1,0); (2,1); (3,0)];;
- : int list = [1]
There are no errors, but it gets the wrong answer. That's what I would expect looking at your code.
The error that you are getting is saying that somewhere the compiler is expecting an int -> bool function, but you are giving it an int. The reason you get this error is because you have an equality (f = snd x), where f is of type int -> bool and snd x is of type int. both arguments given to the equality must be of the same type. Instead, what you want to do is simply branch on the result of applying f to the second element of x, such as:
let rec filter f = function
| []->[]
| x::l -> if f (snd x) then fst x :: filter f l else [];;
That said, I would recommend using pattern matching instead of fst and snd, such as:
let rec filter f l =
match l with
| [] -> []
| (x,y)::l -> if f y then x :: filter f l else filter f l
Note that f y will return something of type bool, which will then determine which branch to take.
Altough Matts answer is right. It's good to just reuse existing functions instead of writing a special from the ground up:
[(1,0);(2,1);(3,0);(4,1)]
|> List.filter (fun (_, x) -> x = 0)
|> List.map fst

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.]