Ocaml noobie Q -- how to use accumulating parameters? - ocaml

I'm trying to learn Ocaml by working on Problem 18 from Project Euler. I know what I want to do, I just can't figure out how to do it.
I've got three lists:
let list1 = [1;2;3;4;5];;
let list2 = [ 6;7;8;9];;
let line = [9999];;
I want to add the numbers list2 to the max adjacent number in list1, IOW I would add 6+2, 7+3, 8+4 and 9+5 to get a list [8;10;12;14]. The list line[] is a dummy variable.
Here's my third try:
let rec meld3 l1 l2 accum =
if List.length l2 = 1 then
List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))]
else
(
List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))];
meld3 (tl l1) (tl l2) accum ;
)
;;
let fu = meld3 list1 list2 line ;;
List.iter print_int fu;;
After running this, I would expect line = [9999;8;10;12;14] but instead line = [9999].
OTOH, fu prints out as [999914].
When I step through the code, the code is executing as I expect, but nothing is changing; the accum in the else block is never modified.
I just don't get this language. Can anyone advise?

OK, let's break down your code. Here's your original.
let rec meld3 l1 l2 accum =
if List.length l2 = 1 then
List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))]
else
(
List.append accum [ (hd l2 + max (hd l1) (hd (tl l1)))];
meld3 (tl l1) (tl l2) accum ;
)
The first thing I'm going to do is rewrite it so a Caml programmer will understand it, without changing any of the computations. Primarily this means using pattern matching instead of hd and tl. This transformation is not trivial; it's important to simplify the list manipulation to make it easier to identify the problem with the code. It also makes it more obvious that this function fails if l2 is empty.
let rec meld3 l1 l2 accum = match l1, l2 with
| x1::x2::xs, [y] -> (* here the length of l2 is exactly 1 *)
List.append accum [ y + max x1 x2 ]
| x1::x2::xs, y::ys -> (* here the length of l2 is at least 1 *)
( List.append accum [ y + max x1 x2 ]
; meld3 (x2::xs) ys accum
)
Now I think the key to your difficulty is the understanding of the semicolon operator. If I write (e1; e2), the semantics is that e1 is evaluated for side effect (think printf) and then the result of e1 is thrown away. I think what you want instead is for the result of e1 to become the new value of accum for the recursive call. So instead of throwing away e1, we make it a parameter (this is the key step where the computation actually changes):
let rec meld3 l1 l2 accum = match l1, l2 with
| x1::x2::xs, [y] -> (* here the length of l2 is exactly 1 *)
List.append accum [ y + max x1 x2 ]
| x1::x2::xs, y::ys -> (* here the length of l2 is at least 1 *)
(
meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
)
Next step is to observe that we've violated the Don't Repeat Yourself principle, and we can fix that by making the base case where l2 is empty:
let rec meld3 l1 l2 accum = match l1, l2 with
| x1::x2::xs, [] -> (* here the length of l2 is 0 *)
accum
| x1::x2::xs, y::ys -> (* here the length of l2 is at least 1 *)
(
meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
)
We then clean up a bit:
let rec meld3 l1 l2 accum = match l1, l2 with
| _, [] -> accum
| x1::x2::xs, y::ys -> meld3 (x2::xs) ys (List.append accum [ y + max x1 x2 ])
Finally, the repeated calls to append make the code quadratic. This is a classic problem with accumulating parameters and has a classic solution: accumulate the answer list in reverse order:
let rec meld3 l1 l2 accum' = match l1, l2 with
| _, [] -> List.rev accum'
| x1::x2::xs, y::ys -> meld3 (x2::xs) ys (y + max x1 x2 :: accum')
I've changed the name accum to accum'; the prime is conventional for a list in reverse order. This last version is the only version I have compiled, and I haven't tested any of the code. (I did test the code in my other answer).
I hope this answer is more helpful.

Well, I think you haven't grasped the essence of functional programming: instead of calling List.append and throwing the value away, you need to pass that value as the parameter accum to the recursive call.
I would tackle this problem by decoupling the triangle geometry from the arithmetic. The first function takes two lists (rows of the triangle) and produces a new list of triples, each containing and element plus that element's left and right child. Then a simple map produces a list containing the sum of each element with its greater child:
(* function to merge a list l of length N with a list l' of length N+1,
such that each element of the merged lists consists of a triple
(l[i], l'[i], l'[i+1])
*)
let rec merge_rows l l' = match l, l' with
| [], [last] -> [] (* correct end of list *)
| x::xs, y1::y2::ys -> (x, y1, y2) :: merge_rows xs (y2::ys)
| _ -> raise (Failure "bad length in merge_rows")
let sum_max (cur, left, right) = cur + max left right
let merge_and_sum l l' = List.map sum_max (merge_rows l l')
let list1 = [1;2;3;4;5]
let list2 = [ 6;7;8;9]
let answer = merge_and_sum list2 list1
If you are working on Euler 18, I advise you to look up "dynamic programming".

Related

F# Splitting a list

I am new to F# & tuples and I am trying to split a list into three lists of tuples using recursion and matching.
For example, a list of [1; 2; 3] would return:
l1 = [1]
l2 = [2]
l3 = [3]
or
[1;2;3;4;5;6;7]:
l1 = [1;2;3]
l2 = [4; 5]
l3 = [6; 7]
So far my code starts out as
let rec split x =
match x with
| _ -> [], [], []
I'm not sure where to start when inserting elements into each list.
The most basic approach would be to walk over the list, process the rest of it recursively and then append the current element to one of the three returned lists. You will need to add an extra parameters i to the function to keep track of how far in the list you are (and then use this to determine where should the current elemnt go). The general structure in the most basic form is:
let split l =
let length = List.length l
let rec loop i l =
match l with
| [] ->
// Empty list just becomes a triple of empty lists
[], [], []
| x::xs ->
// Process the rest of the list recursively. This
// gives us three lists containing the values from 'xs'
let l1, l2, l3 = loop (i + 1) xs
// Now comes the tricky bit. Here you need to figure out
// whether 'x' should go into 'l1', 'l2' or 'l3'.
// Then you can append it to one of them using something like:
l1, x::l2, l3
// Walk over the list, starting with index 'i=0'
loop 0 l
What to do about the tricky bit? I do not have a solution that works exactly as you wanted, but the following is close - it simply looks whether i is greater than 1/3 of the length or 2/3 of the length:
let split l =
let length = List.length l
let rec loop i l =
match l with
| [] -> [], [], []
| x::xs ->
let l1, l2, l3 = loop (i + 1) xs
if i >= length / 3 * 2 then l1, l2, x::l3
elif i >= length / 3 then l1, x::l2, l3
else x::l1, l2, l3
loop 0 l
This will always create groups of length / 3 and put remaining elements in the last list:
split [1..3] // [1], [2], [3]
split [1..4] // [1], [2], [3; 4]
split [1..5] // [1], [2], [3; 4; 5]
split [1..6] // [1; 2], [3; 4], [5; 6]
You should be able to adapt this to the behaviour you need - there is some fiddly calculation that you need to do to figure out exactly where the cut-off points are, but that's a matter of getting the +/-1s right!
There is a function for that in the List module.
You can test it easily in F# interactive (fsi).
let input = [1;2;3];;
let output = List.splitInto 3 input;;
output;;
val it : int list list = [[1]; [2]; [3]]
So it returns a list of lists.
If you want to do it by hand, you can still use other list functions (which might be good exercise in itself):
let manualSplitInto count list =
let l = List.length list
let n = l / count
let r = l % count
List.append
[(List.take (n+r) list)]
(List.unfold (fun rest ->
match rest with
| [] -> None
| _ -> let taken = min n (List.length rest)
Some (List.take taken rest, List.skip taken rest))
(List.skip (n+r) list))
Here, List.unfold does the iteration (recursing) part for you.
So, if you really want to train working with recursive functions, you will end up writing your own List.unfold replacement or something more tailored to your concrete use case.
let pedestrianSplitInto count list =
let l = List.length list
let n = l / count
let r = l % count
let rec step rest acc =
match rest with
| [] -> acc
| _ ->
let taken = min n (List.length rest)
step (List.skip taken rest) ((List.take taken rest) :: acc)
List.rev (step (List.skip (n+r) list) [List.take (n+r) list])
Please observe how similar the implementation of function step is to the lambda given to List.unfold in manualSplitInto.
If you also do not want to use functions like List.take or List.skip, you will have to go even lower level and do element wise operations, such as:
let rec splitAtIndex index front rear =
match index with
| 0 -> (List.rev front, rear)
| _ -> splitAtIndex (index - 1) ((List.head rear) :: front) (List.tail rear)
let stillLivingOnTreesSplitInto count list =
let l = List.length list
let n = l / count
let r = l % count
let rec collect result (front,rear) =
match rear with
| [] -> (front :: result)
| _ -> collect (front :: result) (splitAtIndex n [] rear)
let x = splitAtIndex (n+r) [] list
collect [] x |> List.rev
If you know it will always be triplets then this should work.
let xs = [1..7]
let n = List.length xs
let y = List.mapi (fun i x -> (x, 3 * i / n)) xs
List.foldBack (fun (x, i) (a,b,c) -> match i with 0 -> (x::a,b,c) | 1 -> (a,x::b,c) | 2 -> (a,b,x::c)) y (([],[],[]))

Splitting a list using an index

I have a list of integers named t that has an even length n = List.length t. I want to get two lists, the partition of t from index 0 to (n / 2 - 1), and the partition of t from index (n / 2) to (n-1). In other words, I want to split the list t in two parts, but I cannot find anything that does that in the List module (there is List.filter, but it does not filter by index, it takes a function instead).
An example of what I want to do:
let t = [8 ; 66 ; 4 ; 1 ; -2 ; 6 ; 4 ; 1] in
(* Split it to get t1 = [ 8 ; 66 ; 4 ; 1] and t2 = [-2 ; 6 ; 4 ; 1] *)
For now,I have something like this
let rec split t1 t2 n =
match t1 with
| hd :: tl when (List.length tl > n) -> split tl (hd :: t2) n;
| hd :: tl when (List.length tl = n) -> (t1,t2);
| _ -> raise (Failure "Unexpected error");;
let a = [1;2;3;4;7;8];;
let b,c = split a [] (List.length a / 2 - 1);;
List.iter (fun x -> print_int x) b;
print_char '|';
List.iter (fun x -> print_int x) c;
Output is:
478|321, the order has been reversed!
Calculating the length of the list requires walking the list, so it takes time that's linear in the length of the list. Your attempt calculates the length of the remaining list at each step, which makes the total running time quadratic. But you actually don't need to do that! First you calculate the total length of the list. After that, the place to cut is halfway from the beginning, which you can locate by incrementing a counter as you go through the list.
As for the reversal, let's look at what happens to the first element of the list. In the first call to split, the accumulator t2 is the empty list, so h gets put at the end of the list. The next element will be placed before that, and so on. You need to put the first element at the head of the list, so prepend it to the list built by the recursive call.
let rec split_at1 n l =
if n = 0 then ([], l) else
match l with
| [] -> ([], []) (*or raise an exception, as you wish*)
| h :: t -> let (l1, l2) = split_at1 (n-1) t in (h :: l1, l2);;
let split_half1 l = split_at1 (List.length l / 2) l;;
This operates in linear time. A potential downside of this implementation is that the recursive call it makes is not a tail call, so it will consume a large amount of stack on large lists. You can fix this by building the first half as an accumulator that's passed to the function. As we saw above, this creates a list in reverse order. So reverse it at the end. This is a common idiom when working with lists.
let rec split_at2 n acc l =
if n = 0 then (List.rev acc, l) else
match l with
| [] -> (List.rev acc, [])
| h :: t -> split_at2 (n-1) (h :: acc) t;;
let split_half2 l = split_at2 (List.length l / 2) [] l;;

Split list into two

I would like to implement a function that takes as input a size n and a list. This function will cut the list into two lists, one of size n and the rest in another list. I am new to this language and have a hard time learning the syntax.
The main problem I have is that is finding a way to express a size of the list without using any loops or mutable variables.
Can anyone give a me some pointers?
Let's start with the function's type signature. Since it gets n and a list as arguments and returns a pair of lists, you have a function split:
val split : int -> 'a list -> 'a list * 'a list
Here is one approach to implement this function:
let split n xs =
let rec splitUtil n xs acc =
match xs with
| [] -> List.rev acc, []
| _ when n = 0 -> List.rev acc, xs
| x::xs' -> splitUtil (n-1) xs' (x::acc)
splitUtil n xs []
The idea is using an accumulator acc to hold elements you have traversed and decreasing n a long the way. Because elements are prepended to acc, in the end you have to reverse it to get the correct order.
The function has two base cases to terminate:
There's no element left to traverse (xs = [] at that point).
You have gone through the first n elements of the list (n decreases to 0 at that time).
Here is a short illustration of how split computes the result:
split 2 [1; 2; 3] // call the auxiliary function splitUtil
~> splitUtil 2 [1; 2; 3] [] // match the 3rd case of x::xs'
~> splitUtil 1 [2; 3] [1] // match the 3rd case of x::xs'
~> splitUtil 0 [3] [2; 1] // match the 2nd case of n = 0 (base case)
~> List.rev [2; 1], [3] // call List.rev on acc
~> [1; 2], [3]
let split n list =
let rec not_a_loop xs = function
| (0, ys) | (_, ([] as ys)) -> (List.rev xs), ys
| (n, x::ys) -> not_a_loop (x::xs) (n-1, ys)
not_a_loop [] (n, list)
New solution - splitAt is now built into List and Array. See commit around 2014 on github. I noticed this today while using F# in VS.2015
Now you can simply do this...
let splitList n list =
List.splitAt n list
And as you might expect the signature is...
n: int -> list: 'a list -> 'a list * 'a list
Example usage:
let (firstThree, remainder) = [1;2;3;4;5] |> (splitList 3)
printfn "firstThree %A" firstThree
printfn "remainder %A" remainder
Output:
firstThree [1; 2; 3]
remainder [4; 5]
Github for those interested: https://github.com/dsyme/visualfsharp/commit/1fc647986f79d20f58978b3980e2da5a1e9b8a7d
One more way, using fold:
let biApply f (a, b) = (f a, f b)
let splitAt n list =
let splitter ((xs, ys), n') c =
if n' < n then
((c :: xs, ys), n' + 1)
else
((xs, c :: ys), n' + 1)
List.fold splitter (([], []), 0) list
|> fst
|> biApply List.rev
Here is a great series on folds than you can follow to learn more on the topic.

Linked list partition function and reversed results

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

Most elegant combinations of elements in F#

One more question about most elegant and simple implementation of element combinations in F#.
It should return all combinations of input elements (either List or Sequence).
First argument is number of elements in a combination.
For example:
comb 2 [1;2;2;3];;
[[1;2]; [1;2]; [1;3]; [2;2]; [2;3]; [2;3]]
One less concise and more faster solution than ssp:
let rec comb n l =
match n, l with
| 0, _ -> [[]]
| _, [] -> []
| k, (x::xs) -> List.map ((#) [x]) (comb (k-1) xs) # comb k xs
let rec comb n l =
match (n,l) with
| (0,_) -> [[]]
| (_,[]) -> []
| (n,x::xs) ->
let useX = List.map (fun l -> x::l) (comb (n-1) xs)
let noX = comb n xs
useX # noX
There is more consise version of KVB's answer:
let rec comb n l =
match (n,l) with
| (0,_) -> [[]]
| (_,[]) -> []
| (n,x::xs) ->
List.flatten [(List.map (fun l -> x::l) (comb (n-1) xs)); (comb n xs)]
The accepted answer is gorgeous and quickly understandable if you are familiar with tree recursion. Since elegance was sought, opening this long dormant thread seems somewhat unnecessary.
However, a simpler solution was asked for. Iterative algorithms sometimes seem simpler to me. Furthermore, performance was mentioned as an indicator of quality, and iterative processes are sometimes faster than recursive ones.
The following code is tail recursive and generates an iterative process. It requires a third of the amount of time to compute combinations of size 12 from a list of 24 elements.
let combinations size aList =
let rec pairHeadAndTail acc bList =
match bList with
| [] -> acc
| x::xs -> pairHeadAndTail (List.Cons ((x,xs),acc)) xs
let remainderAfter = aList |> pairHeadAndTail [] |> Map.ofList
let rec comboIter n acc =
match n with
| 0 -> acc
| _ ->
acc
|> List.fold (fun acc alreadyChosenElems ->
match alreadyChosenElems with
| [] -> aList //Nothing chosen yet, therefore everything remains.
| lastChoice::_ -> remainderAfter.[lastChoice]
|> List.fold (fun acc elem ->
List.Cons (List.Cons (elem,alreadyChosenElems),acc)
) acc
) []
|> comboIter (n-1)
comboIter size [[]]
The idea that permits an iterative process is to pre-compute a map of the last chosen element to a list of the remaining available elements. This map is stored in remainderAfter.
The code is not concise, nor does it conform to lyrical meter and rhyme.
A naive implementation using sequence expression. Personally I often feel sequence expressions are easier to follow than other more dense functions.
let combinations (k : int) (xs : 'a list) : ('a list) seq =
let rec loop (k : int) (xs : 'a list) : ('a list) seq = seq {
match xs with
| [] -> ()
| xs when k = 1 -> for x in xs do yield [x]
| x::xs ->
let k' = k - 1
for ys in loop k' xs do
yield x :: ys
yield! loop k xs }
loop k xs
|> Seq.filter (List.length >> (=)k)
Method taken from Discrete Mathematics and Its Applications.
The result returns an ordered list of combinations stored in arrays.
And the index is 1-based.
let permutationA (currentSeq: int []) (n:int) (r:int): Unit =
let mutable i = r
while currentSeq.[i - 1] = n - r + i do
i <- (i - 1)
currentSeq.[i - 1] <- currentSeq.[i - 1] + 1
for j = i + 1 to r do
currentSeq.[j - 1] <- currentSeq.[i - 1] + j - i
()
let permutationNum (n:int) (r:int): int [] list =
if n >= r then
let endSeq = [|(n-r+1) .. n|]
let currentSeq: int [] = [|1 .. r|]
let mutable resultSet: int [] list = [Array.copy currentSeq];
while currentSeq <> endSeq do
permutationA currentSeq n r
resultSet <- (Array.copy currentSeq) :: resultSet
resultSet
else
[]
This solution is simple and helper function costs constant memory.
My solution is less concise, less effective (altho, no direct recursion used) but it trully returns all combinations (currently only pairs, need to extend filterOut so it can return a tuple of two lists, will do little later).
let comb lst =
let combHelper el lst =
lst |> List.map (fun lstEl -> el::[lstEl])
let filterOut el lst =
lst |> List.filter (fun lstEl -> lstEl <> el)
lst |> List.map (fun lstEl -> combHelper lstEl (filterOut lstEl lst)) |> List.concat
comb [1;2;3;4] will return:
[[1; 2]; [1; 3]; [1; 4]; [2; 1]; [2; 3]; [2; 4]; [3; 1]; [3; 2]; [3; 4]; [4; 1]; [4; 2]; [4; 3]]
Ok, just tail combinations little different approach (without using of library function)
let rec comb n lst =
let rec findChoices = function
| h::t -> (h,t) :: [ for (x,l) in findChoices t -> (x,l) ]
| [] -> []
[ if n=0 then yield [] else
for (e,r) in findChoices lst do
for o in comb (n-1) r do yield e::o ]