2

I was working through the answers to Example of the difference between List.fold and List.foldBack trying to get my head around the difference between fold and foldBack. I understand the difference in application order now, but there's a difference in side-effects that I don't understand.

I used List.fold and List.foldBack for my testing. My accumulator functions that were basically equivalent to ::, so that accumulation order would matter. The accumulator functions I used were as follows:

let f acc x =
  // printfn "Folding %A into %A" x acc  // Side-effect!
  x :: acc

let f2 x acc =
  // printfn "Folding %A into %A" x acc  // Side-effect!
  x :: acc

I understand from the F# reference that:

List.fold f [] [1; 2; 3; 4; 5] = (f (f (f (f (f [] 1) 2) 3) 4) 5)

and:

List.foldBack f2 [] [1; 2; 3; 4; 5] = (f2 1 (f2 2 (f2 3 (f2 4 (f2 5 [])))))

should both return true, and they do. Great, I thought; I understand how it works. But just to make sure, I uncommented the side-effect lines from f and f2 and ran List.fold f and List.foldBack f2 again. Result of List.fold f [] [1; 2; 3; 4; 5] with the printfn line uncommented:

Folding 1 into []
Folding 2 into [1]
Folding 3 into [2; 1]
Folding 4 into [3; 2; 1]
Folding 5 into [4; 3; 2; 1]
val it : bool = true

Result of List.foldBack f2 [] [1; 2; 3; 4; 5] with the printfn line uncommented:

val it : bool = true

I was expecting "Folding N into [list]" to show up in both cases. But List.fold executed the side effects of its accumulator function, and List.foldBack did not.

Why is there a difference in side-effect execution between the two forms of fold?

Community
  • 1
  • 1
rmunn
  • 34,942
  • 10
  • 74
  • 105

1 Answers1

6

You have the arguments in the wrong order.

It should be

> List.foldBack f2  [1; 2; 3; 4; 5] [];;
Folding 5 into []
Folding 4 into [5]
Folding 3 into [4; 5]
Folding 2 into [3; 4; 5]
Folding 1 into [2; 3; 4; 5]
val it : int list = [1; 2; 3; 4; 5]
John Palmer
  • 25,356
  • 3
  • 48
  • 67
  • Oh, I see it now. That makes more sense -- that way `foldBack` takes its arguments in the same order that its accumulator function expects (input list first in `foldBack`, input item first in accumulator function). Such a simple thing to miss. Thanks! – rmunn Feb 05 '16 at 09:04
  • 2
    That is made that way in order to avoid mistakes: usually your accumulator and your list would be of different types, and so if you mess up the order of the arguments, it won't compile. – Fyodor Soikin Feb 05 '16 at 09:10