The folds really help us, not confuse us. They capture a specific recursion pattern for sequential reuse. Folds are defined abstractly, and they are most easily understood abstractly. The only reason to understand the specifics of your language folds implementation is to make sure that the implementation is valid.
Whenever we have a specific recursion pattern (entry in equational pseudo-code),
foo(xs) = matches xs with Empty -> zero Cons(head,tail) -> comb(head, foo(tail))
where we combine the list title with the recursive result of calling foo at the tail of the list, we have a (right) fold, and calling foo(xs) is the same as calling foldr(comb, zero, xs) . How exactly this is implemented in our language of choice does not matter.
As you can see, the union function (operator or something else) should take the "current element" of the list as the first argument, and the recursive result as the last. Only when there are no more elements in the list, the zero value is used instead of the recursive result, initiating the chain of comb calculations performed on the return trip from the case of the recursion base, Empty .
So, when reading the definitions of folding, we always consider the first argument of the union function as "the current element , mentally, and the last as the " recursive result of processing the rest of the list ".
Why is this wording about the "current" element? Because, presenting our list [a,b,c,...,n] , the call to foldr(comb, z, [a,b,c,...,n]) matches the above pattern in the same way as call
comb(a, foldr(comb, z, [b,c,d,...,n])) == comb(a, comb(b, comb(c, ......, comb(n, z)......)))
This, in a certain sense, is the definition of the right times on lists, aka, the catamorphism of a list.
Racket adds to this the ability to simultaneously stack multiple lists in parallel. Naturally, the arrangement of the arguments to the union function remains unchanged. all arguments, but the latter correspond to the current elements, each of each argument list; and the last argument is a recursive result to combine them.
A similar but different pattern
bar(xs) = matches xs with Empty -> zero Cons(head,tail) -> comb(head, tail, bar(tail))
which is known as parametrism (see maplist vs. mapcar in Common Lisp).
Since both capture recursions, zero corresponds to the base case of inductive data definition, we recurs to:
List of 'a = Empty or Cons('a, List of 'a)
Starting from the base case, we get a double pattern, creating a value before the recursive call, aot after it, as mentioned above, with
baz(zero, xs) = matches xs with Empty -> zero Cons(head,tail) -> baz( comb(head, zero), tail)
which you will recognize as the left fold (and zero no longer the base value), but the value that is built on the go is ndash; or accumulates, and finally returns when the Empty event occurs).
So, this is just the difference between (1+(2+(3+...(n+0)...))) with the right button and (...(((0+1)+2)+3)...+n) , on the left (showing it with the help, the order of the arguments is reversed, for the essence of the view) . One result will be the same as the other when (+) is an associative operation. Which, for numbers, is.
See also this answer .