Why does this function accept the 2nd param - ocaml

The function aux only has one param n. Why can it accept list at the bottom?
# let length list =
let rec aux n = function
| [] -> n
| _ :: t -> aux (n + 1) t
in
aux 0 list;;
val length : 'a list -> int = <fun>

The function expression produces a function of one argument.
# function [] -> 0 | _ -> 1;;
- : 'a list -> int = <fun>
Now, if you write a function f that takes a parameter n, and whose body contains function, as follows:
# let f n = function [] -> 0 | _ -> n;;
val f : int -> 'a list -> int = <fun>
Then f is a function that takes n and returns a function of a single argument.
# f 3;;
- : '_weak1 list -> int = <fun>
The returned value is a function that takes a list of some unknown type of values, and returns an integer (the _weak prefix is related to Weak Type Variables, this is not important here).
Since the returned value is a function, you can apply it:
# (f 3) ["test"];;
- : int = 3
You can drop the parentheses around f 3 because that's how function application is grouped by default:
# f 3 ["test"];;
- : int = 3
So what looks like a function taking two arguments is in fact a function taking one argument, evaluating to a function to which we apply the second argument.
(See also Currying)

The function keyword introduces a function which takes a single argument, which it pattern matches.
This is equivalent to:
let length lst =
let rec aux n lst =
match lst with
| [] -> n
| _ :: t -> aux (n + 1) t
in
aux 0 lst
Or...
let length lst =
let rec aux n =
fun lst ->
match lst with
| [] -> n
| _ :: t -> aux (n + 1) t
in
aux 0 lst

function keyword will match the last argument, even it’s not declared in the left side of =.
Compare with match .. with, the match needs the argument name show up.

Related

Different ways of declaring a function

When declaring a function, I've 3 different ways:
let f x = ...
let f = (fun x -> ...)
let f = function
| ... -> (pattern matching)
It's this last one that I don't fully understand how it works.
I was doing a function that, considering a list (we'll assume it has integers in it but could be anything), reverses it, pretty basic, but with a complexity of O(n). After struggling for an hour at least I check the answer, and it is written like this:
let reverse lst =
let rec aux acc = function
| [] -> acc
| hd :: tl -> aux (hd :: acc) tl
in
aux [] lst
I thought that using the key word function was just another way of doing patter matching, but when I do this:
let reverse lst =
let rec aux acc =
match aux with
| [] -> acc
| hd :: tl -> aux (hd :: acc) tl
in
aux [] lst
It doesn't work, and idk why. On top of that, why can we add tl at the end of the first function? Isn't aux a single argument function?
There are a few problems with this question. First, the code you give as the solution for reverse is not valid OCaml. It matches aux (which is a function) against list patterns. Most likely aux was supposed to be acc. But even so it doesn't seem right because it should have two arguments (the accumulated result and the input that still needs to be processed).
Second, your two code examples are the same. You seem to be saying that one works and one doesn't work. That doesn't make sense since they're the same.
IMHO you need to rewrite the question if you want to get a helpful answer.
Ocaml uses currying, which means that a two-argument function is the same thing that a function whose return value is a function.
To define a two-argument function, you can combine all the ways you know of creating one-argument functions:
let f x y = x + y
let f x = (fun y -> x + y)
let f x = function
| y -> x + y
let f = (fun x -> (fun y -> x + y))
let f = function
| x -> function
| y -> x + y
let f x = (let g y = x + y in g)
etc, etc.
All these definitions for f lead to the same result:
val f : int -> int -> int = <fun>
# f 3 4;;
- : int = 7
Note that the signature of f is:
val f : int -> int -> int = <fun>
If we added parentheses to better understand this signature, it would be this:
val f : int -> (int -> int) = <fun>
Meaning that f is a one-argument function whose return value is a one-argument function whose return value is an int.
Indeed, if we partially apply f:
# f 3;;
- : int -> int = <fun>
# let add_three = f 3;;
val add_three : int -> int = <fun>
# add_three 4;;
- : int = 7
The code you give at the end of your question is wrong. It's most likely intended to be this:
let reverse lst =
let rec aux acc l =
match l with
| [] -> acc
| hd :: tl -> aux (hd :: acc) tl
in
aux [] lst;;
val reverse : 'a list -> 'a list = <fun>
# reverse [1;2;3;4;5];;
- : int list = [5; 4; 3; 2; 1]

Let OCaml function work with lists and ints

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

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

Understanding the structure of Ocaml

As I am going through the website:
http://www.cs.princeton.edu/courses/archive/fall14/cos326/sec/03/precept03_sol.ml
I have got a question according to the Ocaml structure. To be more specific, I have questions according to the code:
let rec reduce (f:'a -> 'b -> 'b) (u:'b) (xs:'a list) : 'b =
match xs with
| [] -> u
| hd::tl -> f hd (reduce f u tl);;
What does the f hd do at the very last line? (I understand that reduce f u tl is calling the function itself again.)
My second question is how to use a function to implement another function in Ocaml. For the code:
let times_x (x: int) (lst: int list) : int list =
map (fun y -> y*x) lst
What does fun y -> y*x do? what does lst do at the end of the code?
Thank you for the help!
The code that has been provided is a reduce function that takes three parameters - a function that maps inputs of type 'a and 'b to an output of type 'b, a value of type 'b, and as list of elements of type 'a.
For example, the length example from the lecture:
let length (lst: int list) : int =
reduce (fun _ len -> len + 1) 0 lst
The first parameter to reduce is a function that, when given two parameters, discards the first one and returns the second parameter incremented by one. The second is a value (0) to be used as an accumulator. The third is a list to find the length of.
The behavior of this recursive reduce function is to return the second parameter (an accumulator as used in the length example) once the provided list is empty, and otherwise run the provided function using the head of the list and the recursed value.
Once again going to the length example, say we give it a list with a single element [1].
Our call to length becomes reduce (fun _ len -> len + 1) 0 [1]
Recall reduce:
let rec reduce (f:'a -> 'b -> 'b) (u:'b) (xs:'a list) : 'b =
match xs with
| [] -> u
| hd::tl -> f hd (reduce f u tl);;
First, we match [1] against [], which fails. Since it is a non-empty list, we run f hd (reduce f u tl)
Recall that f is the parameter that length provided: fun _ len -> len + 1
Therefore, we effectively run the following:
(fun _ len -> len + 1) 1 (reduce (fun _ len -> len + 1) 0 [])
In this case, the length function discards the first parameter since the values in the list are not necessary to know the length of the list.
The recursive portion will match against [] and return the value of u at the time, which is 0.
Therefore, one level up, (fun _ len -> len + 1) 1 (reduce (fun _ len -> len + 1) 0 []) becomes (fun _ len -> len + 1) 1 0 and returns 0 + 1, simplifying to our expected value 1, which represents the length of the list.
Now, to your second question, in regards to times_x. This performs a mapping. For example, we can map [1;2;3;4;5] to [3;6;9;12;15] with a mapping fun x -> x * 3.
Here times_x is defined as follows:
let times_x (x: int) (lst: int list) : int list =
map (fun y -> y*x) lst
times_x takes an integer and a list. Using the above example, we could call it with times_x 3 [1;2;3;4;5] to get [3;6;9;12;15].
Beyond this I recommend looking into how map and reduce functions work in general.
I hope this answer was adequate at addressing your question.

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