functional-programmingocaml

OCaml - Accumulator Using Fold Left


Learning OCaml from here.

I want to verify if I have understood how this snippet of OCaml code works

List.fold_left (fun acc x -> acc + x) 0 [ 1; 2; 3; 4 ]

I have an intuition that this is an equivalent to the reduce function in Python. Specifically, I think it is equivalent to

reduce(lambda x, y: x + y, [1, 2, 3])

The anonymous function is taking two parameters - acc and x and returns a single value acc + x. I understand that initially, the first argument acc will be 0 but how does it know that the second argument has to be the first element of the list?

What I think is happening is that fold_left provides the two arguments to the anonymous function and then recursively calls itself with new arguments until the list becomes empty.

To confirm this I saw this.

When I define a function like let inc x = x + 1 I get something like val inc : int -> int = <fun> but in this case the signature is : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>

What is 'a and how should I interpret this function signature so that List.fold_right f [a1; ...; an] b becomes f a1 (f a2 (... (f an b) ...))?


Solution

  • You are asking many questions.

    I'm pretty sure that Python reduce is a fold, so your intuition is probably right.

    You ask "how does it know that the second argument has to be the first element of the list?" Unfortunately, I don't think this is a well formed question. There's no "it" that knows anything. Most likely the answer is given by the definition of fold_left. It knows what to do because somebody wrote the code that way :-)

    Here is the definition of fold_left from the standard library:

    let rec fold_left f accu l =
      match l with
        [] -> accu
      | a::l -> fold_left f (f accu a) l
    

    In some sense, this should answer all your questions.

    The type 'a in the type of fold_left is the type of the accumulator. The point is that you can use any type you want for the accumulator. This is why the fold is so powerful. As long as it matches the values accepted and returned by the folded function, it can be anything you want.