3

Can anyone please explain in a very simple way what is List.Fold and List.Foldback in F#. I have read some few books and tried to search online for a simple explanation I still don't understand it.

-This is not a duplicate question and it has not been answered in the other link.

Oluwagbemi Kadri
  • 400
  • 5
  • 15
  • 1
    It doesn't seem to be the same question, that one is focused on when `foldBack` is needed over `fold`, while this one is about understanding `fold`. – AMieres Nov 02 '18 at 17:34
  • 2
    `List.fold (+) 0 [1; 2; 3]` is `((0 + 1) + 2) + 3`. And `List.foldBack (+) [1; 2; 3] 0` is `1 + (2 + (3 + 0))` – TheQuickBrownFox Nov 02 '18 at 19:26

1 Answers1

12

The best way to understand it is with an example. Imagine you have list of numbers and you want to find out the total. In imperative programming you could do this:

let numbers = [ 19 ; 52 ; 35 ; 27]

let mutable total = 0
for n in numbers do
    total <- total + n

printfn "%A" total   // 133

it is a good solution but not functional. Lets use List.fold to do the same:

numbers
|> List.fold (fun total n -> total + n) 0
|> printfn "%A"    // 133

voila! If you squint you can recognize the same elements in both solutions.

  • Your state: total
  • Your folder operation that takes the prior state and an element of the list and returns a new state: total + n
  • Your initial value: 0

Lets look at the signature of List.fold:

val List.fold: 
   folder: 'State -> 'T -> 'State ->
   state : 'State  ->
   list  : 'T list 
        -> 'State

See how the elements match up?

List.foldBack is the same but the elements are fed in reverse order. The order of the parameters is also different.


One of the interesting things about fold is that in many cases it can replace a tail recursive function:

If you didn't have List.fold and wanted to implement a totalF function without mutable, how would you do it? You would need recursion, better yet tail recursion:

let rec totalF total ns =
    match ns with
    | []        ->         total
    | n :: tail -> totalF (total + n) tail

numbers
|> totalF 0
|> printfn "%A"    // 133

Again you can see all the elements as before. In fact if we make total + n into a parameter of totalF:

let rec totalF f total ns =
    match ns with
    | []        -> total
    | n :: tail -> totalF f (f total n) tail

numbers
|> totalF (fun total n -> total + n) 0
|> printfn "%A"    // 133

You get fold, the signature and use are the same:

val totalF: 
   f    : 'a -> 'b -> 'a ->
   total: 'a             ->
   ns   : 'b list        
       -> 'a
AMieres
  • 4,944
  • 1
  • 14
  • 19