I am back to coding in OCaml and I missed it so much. I missed it so much I completely lost my reasoning in this language and I hit a wall today.
What I want to do is the combination of elements between a set of n lists.
I decomposed the problem by first attempting the combination of elements between two list of arbitrary sizes.
Assume we have to lists: l1 = [1;2;3] and l2 = [10,20].
What I want to do is obtain the following list:
l_res = [10;20;20;40;30;60]
I know how to do this using loop structures, but I really want to solve this without them.
I tried the following:
let f l1 l2 =
List.map (fun y -> (List.map (fun x -> x * y) l1) l2
But this does not seem to work. The type I get is f : int list -> int list -> int list list but I want f : int list -> int list -> int list
I tried already many different approaches I feel I am over complicating.
What did I miss?
What you are missing is that List.map f [a; b; c] gives [f a; f b; f c] so what you'll get from your function will be
f [a; b; c] [d; e] = [[ad; ae]; [bd; be]; [cd; ce]]
but you want
f [a; b; c] [d; e] = [ad; ae; bd; be; cd; ce]
so you need to use an other iterator, i.e. :
let f l1 l2 =
let res = List.fold_left (fun acc x ->
List.fold_left (fun acc y -> (x * y) :: acc) acc l2
) [] l1 in
List.rev res
or to flatten your result :
val concat : 'a list list -> 'a list
Concatenate a list of lists. The elements of the argument are all
concatenated together (in the same order) to give the result. Not
tail-recursive (length of the argument + length of the longest
sub-list).
val flatten : 'a list list -> 'a list
Same as concat. Not tail-recursive (length of the argument + length of
the longest sub-list).
Some Core-flavoured answers:
open Core.Std
let f1 l1 l2 =
List.map (List.cartesian_product l1 l2) ~f:(fun (x, y) -> x * y)
let f2 l1 l2 =
List.concat_map l1 ~f:(fun x -> List.map l2 ~f:(fun y -> x * y))
let f4 l1 l2 =
let open List.Monad_infix in
l1 >>= fun x ->
l2 >>| fun y ->
x * y
The last answer explicitly (and arguably the two other answers implicitly) makes use of the list monad, which this is a textbook use case of. I couldn't find the list monad in Batteries, which is possibly not so surprising as it's much less widely used than (say) the option or result monads.
let f l1 l2 =
let multiply x = List.map (( * )x) l2 in
l1 |> List.map multiply
|> List.concat
Related
I have one task in hand that I am 90% done with it but just don't quite know how to finish it. So the task is as follows : " Write a non-recursive function which takes a function, and two lists as an input, and returns a third list which contains the result of the function applied on all possible pairs of elements from both input lists." So I have to get it as below.
# cart_fun ( * ) [1;2;2;6;3;9;1] [2;3];; -: int list = [2; 3; 4; 6; 4; 6; 12; 18; 6; 9; 18; 27; 2; 3]
My struggle is that I don't know how to make a function substitution. Here is my code.
let cart_fun list1 list2 =
let res = List.fold_left (fun acc x -> List.fold_left (fun acc y -> (x * y) :: acc) acc list2) [] list1
in List.rev res;;
But I would like that in part (x*y) the multiplication be given as an argument before the lists.
Thank you for your help in advance.
Most of the journey has already been made! Well done!
As you can see by using the fold_left function, in OCaml (as in other functional languages) you can pass functions as arguments (and even return them), which is why you can provide fold_left with an accumulation function. Here is your code:
let cart_fun list1 list2 =
let res = List.fold_left (fun acc x ->
List.fold_left (fun acc y -> (x * y) :: acc) acc list2)
[] list1
in List.rev res;;
Even if the code is very good, let's rephrase it a bit to see it more clearly!
let cart_fun list1 list2 =
let process_list_2 fst_acc =
List.fold_left
(fun snd_acc y -> (x * y) :: snd_acc)
fst_acc
list2
in
let result = List.fold_left (fun acc x -> process_list_2 acc x) [] list1 in
List.rev result
As you may have realised: (fun acc x -> process_list_2 acc x) is, in fact, identical to process_list_2 so, let's rephase one more time:
let cart_fun list1 list2 =
let process_list_2 fst_acc =
List.fold_left
(fun snd_acc y -> (x * y) :: snd_acc)
fst_acc
list2
in
let result = List.fold_left process_list_2 [] list1 in
List.rev result
But hey, we want to generalise cart_fun in ordrer to have, instead of cart_fun list1 list2, we want cart_fun modifier list1 list2, where modifier is just a function... So, no problem, let's changing this part of the code:
let cart_fun modifier list1 list2 =
let process_list_2 fst_acc =
List.fold_left
(fun snd_acc y -> (modifier x y) :: snd_acc)
fst_acc
list2
in
let result = List.fold_left process_list_2 [] list1 in
List.rev result
And voila! As you can see, there wasn't much modification required. Just keep in mind that in OCaml, you can consider that a variable will contain a function; which is pretty cool!
Btw, the "general behaviour" that you want to capture looks a lot like what we call "a comprehension" (like in Python and Haskell). And since OCaml 4.10, there is a function in list module which allow you to write easily comprehension : List.concat_map val concat_map : ('a -> 'b list) -> 'a list -> 'b list which has the same effect than mapping over a list of 'a, producing a list of list of b and flatten the list into a list of b.
So you can see your cartesian product as :
let cart_fun modifier list1 list2 =
List.concat_map (fun x ->
List.concat_map (fun y ->
[modifier x y]
) list2
) list1
But as you can see... it's not much more readable than before! Fortunately, in addition to passing functions as arguments, OCaml also allows you to describe your own operators. For example, here we could describe an operator to simplify the chaining of concat_map which we would randomely call... >>= :
let (>>=) list f = List.concat_map f list
let cart_fun modifier list1 list2 =
list1 >>= fun x ->
list2 >>= fun y -> [modifier x y]
Awesome, can we go deeper in the readability ? Of course, since OCaml 4.08, you can define let operators. So defining your own let with a suffix. For example, here, let's define let* (which will be exactly the same of >>=)
let (let*) list f = List.concat_map f list
(* So `let* x = l in g x` is the same of `l >>= fun x -> g x` *)
nice no?
And now, we can rewrite our example:
let cart_fun modifier list1 list2 =
let* x = list1 in
let* y = list2 in
[modifier x y]
And voila ! Even:
let cart_fun modifier list1 list2 =
let process_list_2 fst_acc =
List.fold_left
(fun snd_acc y -> (modifier x y) :: snd_acc)
fst_acc
list2
in
let result = List.fold_left process_list_2 [] list1 in
List.rev result
Is "more direct" I think it is nice to see how OCaml is expressive!
So I am currently trying to figure out how to write a function where it takes 2 lists of equal lengths and multiplies the same position of both lists through folding, and returns the result as a new List.
eg) let prodList [1; 2; 3] [4; 5; 6] ;;
==> (through folding) ==> [1*4; 2*5; 3*6]
==> result = [4; 10; 18]
I feel like I need to use List.combine, since it will put the values that need to be multiplied into tuples. After that, I can't figure out how to break apart the tuple in a way that allows me to multiply the values. Here is what I have so far:
let prodLists l1 l2 =
let f a x = (List.hd(x)) :: a in
let base = [] in
let args = List.rev (List.combine l1 l2) in
List.fold_left f base args
Am I on the right track?
You can use fold_left2 which folds two lists of the same length. The documentation can give you more details (https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html):
val fold_left2 : ('a -> 'b -> 'c -> 'a) -> 'a -> 'b list -> 'c list -> 'a
List.fold_left2 f a [b1; ...; bn] [c1; ...; cn] is f (... (f (f a b1 c1) b2 c2) ...) bn cn. Raise Invalid_argument if the two lists are determined to have different lengths.
Another way is to fold the output of combine as you have suggested, I would recommend you to try it by yourself before looking at the solution bellow.
Solution:
let prod_lists l s =
List.rev (List.fold_left2 (fun acc a b -> (a * b) :: acc) [] l s);;
let prod_lists' l s =
List.fold_left (fun acc (a, b) -> (a * b) :: acc) [] (List.rev (List.combine l s));;
First let me note using fold to implement this operation seems a bit forced, since you have to traverse both lists at the same time. Fold however combines the elements of a single list. Nonetheless here is an implementation.
let e [] = []
let f x hxs (y::ys) = (x*y) :: hxs ys
let prodList xs ys = List.fold_right f xs e ys
Looks a bit complicated, so let me explain.
Universal Property of fold right
First you should be aware of the following property of fold_right.
h xs = fold_right f xs e
if and only if
h [] = e
h (x::xs) = f x (h xs)
This means that if we write the multiplication of lists in the recursive form below, then we can use the e and f to write it using fold as above. Note though we are operating two lists so h takes two arguments.
Base case - empty lists
Multiplying two empty lists returns an empty list.
h [] [] = []
How to write this in the form above? Just abstract over the second argument.
h [] = fun [] -> []
So,
e = fun [] -> []`
Or equivalently,
e [] = []
Recursive case - non-empty lists
h (x::xs) (y::ys) = x*y :: h xs ys
Or, using just one argument,
h (x::xs) = fun -> (y::ys) -> x*y :: h xs ys
Now we need to rewrite this expression in the form h (x::xs) = f x (h xs). It may seem complicated but we just need to abstract over x and h xs.
h (x::xs) = (fun x hxs -> fun (y::ys) -> x*y :: hxs ys) x (h xs)
so we have that f is defined by,
f = fun x hxs -> fun (y::ys) -> x*y :: hxs ys
or equivalently,
f x hxs (y::ys) = x*y :: hxs ys
Solution as a fold right
Having determined both e and f we just plug then into fold according to the first equation of the property above. And we get,
h xs = List.fold_right f xs e
or equivalently,
h xs ys = List.fold_right f xs e ys
Understanding the implementation
Note that the type of List.fold_right f xs e is int list -> int list, so the fold is building a function on lists, that given some ys will multiply it with the given parameter xs.
For an empty xs you will expect an empty ys and return an empty result so,
e [] = fun [] -> []
As for the recursive case, the function f in a fold_right must implement a solution for x::xs from a solution for xs. So f takes an x of type int and a function hxs of type int list -> int list which implements the multiplication for the tail, and it must implement multiplication for x::xs.
f x hxs = fun (y::ys) -> x*y :: hxs ys
So f constructs a function that multiplies x with y, and then applies to ys the already constructed hxs which multiplies xs to a list.
You mostly have the right idea; you'll want to combine (zip in other languages) the two lists and then map over each tuple:
let prod_lists l1 l2 =
List.combine l1 l2
|> List.map (fun (a, b) -> a * b)
The key is that you can pattern match on that tuple using (a, b).
You can also fold over the combined list, then rev the result, if you don't want to use map.
Is there a library function to find List1 minus elements that appear in List2? I've been googling around and haven't found much.
It doesn't seem too trivial to write it myself. I've written a function to remove a specific element from a list but that's much more simple:
let rec difference l arg = match l with
| [] -> []
| x :: xs ->
if (x = arg) then difference xs arg
else x :: difference xs arg;;
Will this do?
let diff l1 l2 = List.filter (fun x -> not (List.mem x l2)) l1
What I ended up actually doing was just writing another function which would call the first one I posted
let rec difference l arg = match l with
| [] -> []
| x :: xs ->
if (x = arg) then difference xs arg
else x :: difference xs arg;;
let rec list_diff l1 l2 = match l2 with
| [] -> l1
| x :: xs -> list_diff (difference l1 x) xs;;
Although the solution I accepted is much more elegant
I have been trying to wrap my head around fold_left and fold_right. As practice, I have been trying to rewrite a lot of functions in fold_left and fold_right to strengthen my knowledge. For instance, in finding the average of a list, I would calculate the sum and the length of the list using folds.
let sum_l xs = List.fold_left (fun x y -> x + y) 0 xs;;
let len_l xs = List.fold_left (fun x _ -> x + 1) 0 xs;;
And then I would move on to find the average. Here is my question. Is it possible to both these values in one single fold_left? How should I write the anonymous function? Thanks!
You just have to use a pair as your accumulator:
# let sum_and_len xs = List.fold_left (fun (s,l) x -> s+x, l+1) (0,0) xs;;
val sum_and_len : int list -> int * int = <fun>
# sum_and_len [0;1;2;3];;
- : int * int = (6, 4)
I wrote this F# function to partition a list up to a certain point and no further -- much like a cross between takeWhile and partition.
let partitionWhile c l =
let rec aux accl accr =
match accr with
| [] -> (accl, [])
| h::t ->
if c h then
aux (h::accl) t
else
(accl, accr)
aux [] l
The only problem is that the "taken" items are reversed:
> partitionWhile ((>=) 5) [1..10];;
val it : int list * int list = ([5; 4; 3; 2; 1], [6; 7; 8; 9; 10])
Other than resorting to calling rev, is there a way this function could be written that would have the first list be in the correct order?
Here's a continuation-based version. It's tail-recursive and returns the list in the original order.
let partitionWhileCps c l =
let rec aux f = function
| h::t when c h -> aux (fun (acc, l) -> f ((h::acc), l)) t
| l -> f ([], l)
aux id l
Here are some benchmarks to go along with the discussion following Brian's answer (and the accumulator version for reference):
let partitionWhileAcc c l =
let rec aux acc = function
| h::t when c h -> aux (h::acc) t
| l -> (List.rev acc, l)
aux [] l
let test =
let l = List.init 10000000 id
(fun f ->
let r = f ((>) 9999999) l
printfn "%A" r)
test partitionWhileCps // Real: 00:00:06.912, CPU: 00:00:07.347, GC gen0: 78, gen1: 65, gen2: 1
test partitionWhileAcc // Real: 00:00:03.755, CPU: 00:00:03.790, GC gen0: 52, gen1: 50, gen2: 1
Cps averaged ~7s, Acc ~4s. In short, continuations buy you nothing for this exercise.
I expect you can use continuations, but calling List.rev at the end is the best way to go.
I usually prefer Sequences over List as they are lazy and you got List.toSeq and Seq.toList functions to convert between them. Below is the implementation of your partitionWhile function using sequences.
let partitionWhile (c:'a -> bool) (l:'a list) =
let fromEnum (e:'a IEnumerator) =
seq { while e.MoveNext() do yield e.Current}
use e = (l |> List.toSeq).GetEnumerator()
(e |> fromEnum |> Seq.takeWhile c |> Seq.toList)
,(e |> fromEnum |> Seq.toList)
You can rewrite the function like this:
let partitionWhile c l =
let rec aux xs =
match xs with
| [] -> ([], [])
| h :: t ->
if c h then
let (good, bad) = aux t in
(h :: good, bad)
else
([], h :: t)
aux l
Yes, as Brian has noted it is no longer tail recursive, but it answers the question as stated. Incidentally, span in Haskell is implemented exactly the same way in Hugs:
span p [] = ([],[])
span p xs#(x:xs')
| p x = (x:ys, zs)
| otherwise = ([],xs)
where (ys,zs) = span p xs'
A good reason for preferring this version in Haskell is laziness: In the first version all the good elements are visited before the list is reversed. In the second version the first good element can be returned immediately.
I don't think I'm the only one to learn a lot from (struggling with) Daniel's CPS solution. In trying to figure it out, it helped me change several potentially (to the beginner) ambiguous list references, like so:
let partitionWhileCps cond l1 =
let rec aux f l2 =
match l2 with
| h::t when cond h -> aux (fun (acc, l3) -> f (h::acc, l3)) t
| l4 -> f ([], l4)
aux id l1
(Note that "[]" in the l4 match is the initial acc value.) I like this solution because it feels less kludgey not having to use List.rev, by drilling to the end of the first list and building the second list backwards. I think the other main way to avoid .rev would be to use tail recursion with a cons operation. Some languages optimize "tail recursion mod cons" in the same way as proper tail recursion (but Don Syme has said that this won't be coming to F#).
So this is not tail-recursive safe in F#, but it makes my answer an answer and avoids List.rev (this is ugly to have to access the two tuple elements and would be a more fitting parallel to the cps approach otherwise, I think, like if we only returned the first list):
let partitionWhileTrmc cond l1 =
let rec aux acc l2 =
match l2 with
| h::t when cond h -> ( h::fst(aux acc t), snd(aux acc t))
| l3 -> (acc, l3)
aux [] l1