Reputation: 2044
I have written a function:
let rec addAll f l =
match l with
| [] -> 0
| [x] -> x
| hd::tl -> let combined = addAll f tl in
f (hd) combined
;;
I works as titled, it will add all the elements of a list. However, I want to write this program so it is Left associative, so instead of combining the elements [1;2;3] as 1 - (2 - 3), I want it to be: (1 - 2) - 3.
Any hints on how I can make this forward recursive instead of tail? Or how can I make it so this function works as I intend? I know I could just reverse the list, but I want to try another way.
Upvotes: 0
Views: 817
Reputation: 66808
Your code does a right fold. Roughly speaking, it's like this:
let addAll f l = List.fold_right f l 0
You want to change it to a left fold. Roughly speaking you want this:
let addAll f l = List.fold_left f 0 l
Or, slightly more accurately you want:
let addAll f = function
| [] -> 0
| h :: t -> List.fold_left f h t
This second function does seem to do what you want:
# addAll (-) [1;2;3];;
- : int = -4
If you want to write it from scratch (not using List.fold_left
), the easiest way is with an accumulator:
let addAllScratch f l =
let rec iadd f accum l =
match l with
| [] -> accum
| a::l -> iadd f (f accum a) l
in
match l with
| [] -> 0
| h :: t -> iadd f h t
This does do what you want:
# addAllScratch (-) [1;2;3];;
- : int = -4
(In essence, I just inserted the standard definition of List.fold_left
into the code.)
Upvotes: 2
Reputation: 1619
let rec addAll f l =
match l with
| [] -> 0
| [x] -> x
| x::y::tl -> addAll f ((f x y)::tl)
;;
Test
# addAll (fun a b -> Printf.printf "(%d %d)" a b; a+b) [1;2;3];;
(1 2)(3 3)- : int = 6
Upvotes: 1