Problem:Define the function mapf
whose first argument is a unary function, and second argument list. The result is a list of the function applied to each element of the argument list. Write a one-liner using fold_right, and not a recursive function.
Solution:
let mapf fn list = fold_right (fun h t -> fn h :: t) list []
I don't understand how that solves the problem because fold_right computes a function with the list arguments in a recursive way, so it returns a value and not a list. I neither understand what the following notation means:
fun h t -> fn h :: t
Your two questions are related. It's true that fold_right
returns a value, but a list is a value!
The ::
operator adds a new element to the beginning of a list. So the value computed by this application of fold_right
is indeed a list.
Another way to think of this might be as follows. If you use fold_right
with the +
operator you compute a value like so:
fold_right (+) [1; 2; 3] 0 =>
1 + 2 + 3 + 0 =>
6
If you use fold_right
with the ::
operator, you compute a value like so:
fold_right (::) [1; 2; 3] [] =>
1 :: 2 :: 3 :: [] =>
[1; 2; 3]
This isn't theoretical, it works exactly like this in the REPL:
# List.fold_right (+) [1; 2; 3] 0;;
- : int = 6
# List.fold_right (fun a b -> a :: b) [1; 2; 3] [];;
- : int list = [1; 2; 3]
(You need to write fun a b -> a :: b
because the ::
notation can't actuallly be used as a stand-alone function. Unfortunately.)
Note that it's completely legitimate to write a list using the ::
operator yourself:
# 1 :: 2 :: 3 :: [];;
- : int list = [1; 2; 3]
Update
First, fun x y -> expr
is the notation for a "lambda" in OCaml, i.e., for a function literal.
The function fun h t -> fn h :: t
takes two values h
and t
. It applies the function fn
to h, and returns a new list with this new value at the front of t
.
From a typing standpoint, the value h
must be the right type to pass to fn
, and fn
must return a value of the right type to be in the list t
.
You could parenthesize it like this: fun h t -> (fn h) :: t
, if that makes it clearer.
The function fun a b -> a :: b
is similar except that it just puts a
directly onto the list b
. It doesn't apply any function. In essence, it does just what the ::
operator does.
From a typing standpoint, a
has to be the right type to be an element of the list b
.
Update 2
If you're trying to understand what a lambda is, one way of looking at it is that it's just a handy way to write a function that's reasonably small. You can easily write your given code without the lambda:
let mapf fn list =
let helper h t = fn h :: t in
List.fold_right helper list []
Instead of a lambda, this version has a locally declared function named helper
.
Another way of looking at it is that all functions are lambdas. The idiomatic way of writing a function:
let f x y = x + y
is just a handy abbreviation for a version with an explicit lambda:
let f = fun x y -> x + y
So, really, a lambda isn't a special kind of function. It's exactly like any other function. It's just a notational choice.