Operation order in `foldr`

I was looking at this example of foldr


foldr (/) 1 [2,4,8]

… and it divides each number in the list by the accumulator with a final result of 4. So 8/1, 4/8, 2/0.5.

However, before I looked it up I thought it could just as well be: 1/8, 0.125/4, 0.3125/1.

I see it is the way it is but I’m looking for some rule or intuition to guide me rather than just remembering that it works that way.

Is there something to the order other than it was designed that way?

The syntactic sugar obfuscates what is happening. If list were defined as a normal type like this:

data List a = Nil | Cons a (List a)

Then your code would be written as:

foldr (/) 1 (Cons 2 (Cons 4 (Cons 8 Nil)))

Now, foldr is just replacing each occurrence of Cons with (/) and Nil with 1. So you get:

(/) 2 ((/) 4 ((/) 8 1))

Or written in infix form:

2 / (4 / (8 / 1))

I think this is the most natural way to define a fold because it exactly follows the structure of the list.

6 Likes

It was helpful to look at it that way. I can now think it through effortlessly by thinking:

foldr (/) 1 [2,4,8]
  • Put the accumulator on the right

  • Divide right associatively

    2/(4/(8/1))

foldl (/) 16 [8,4,2,1]
  • Put the accumulator on the left

  • Divide left associatively

    (((16/8)/4)/2)/1

Thanks!

1 Like

Also helpful maybe:

https://www.joachim-breitner.de/blog/753-Drawing_foldl_and_foldr

5 Likes