Why do i get infinite type error - haskell

I am trying to implement my own concat using folds and stumbling here. Why do i get "cannot create infinite types" error?
merge2 xs = foldl conc ([]) xs
where conc x y = (x : y)

Look at the type of x and y in the expression x : y - the type of y must be a list of whatever type x is, due to the definition of :. If you try to follow the types of foldl, in particular the type of its accumulator function, you will end up needing a list of lists of lists of...

Here's how you could trick GHCi into showing you the types of interim expressions. First, your original definition,
f xs = foldl conc [] xs where conc x y = (x : y)
gives you an error about "infinite type" "a = [a]". Now, replace conc in foldl with something else:
f xs = foldl g [] xs where conc x y = (x : y) ; g = g
No type errors there! If you still have errors replace every identifier used in some expression with g2 = g2, g3 = g3 etc. Such definitions are equivalent to defining g = undefined, whose use will cause an error, but more importantly for us its type is free to become anything, as needed.
Now the trick is to define it as some simple value, say a Boolean:
f xs = foldl g [] xs where conc x y = (x : y) ; g = True
this gives us an error about type mismatch between "a -> b -> a" and "Bool". We know True has type Bool, so we conclude that g must be of type a -> b -> a. We could find this out directly as well, with :t command:
Prelude> :t foldl
foldl :: (a -> b -> a) -> a -> [b] -> a
-------------
Continuing, we can now compare conc with some simple value:
f xs = foldl g [] xs where conc x y = (x : y) ; g = g ; h = conc == True
Again we get type mismatch error between "a -> [a] -> [a]" and "Bool". True :: Bool (has type Bool), so conc :: a -> [a] -> [a]. And originally we used it where now g is, so their types must match:
g :: a -> b -> a
conc :: a -> [a] -> [a]
------
a ~ [a]
which is impossible.

Related

Haskell: for every even appearance in an array, concatenate an int to the final list

I'm currently trying to write a function that takes as arguments an Int and an array of Ints and for every even value in the array, it concatenates the Int to the final array.
So, something like this:
f 3 [1,2,3,4,5,6] = [1,2,3,3,4,3,5,6,3]
This is the code I imagined would work (I'm just beginning so sorry if it's bad):
f :: Int -> [Int] -> [Int]
f(x,[]) = []
f(x,y)
|even head(y) = (head(y) ++ [x] ++ f(x,drop 1 y)
|otherwise = head(y) ++ f(x,(drop 1 y))
The error I'm getting is "Couldn't match expected type of 'Int' with actual type (a3, [[a3]])'. I understand the parameters types are mismatched, but I'm not sure how a proper syntax would look like here
You use (x, []), so that means the input type would be a tuple, so f :: (Int, [Int]) -> [Int].
I would also use pattern matching instead of head and tail, so:
f :: Int -> [Int] -> [Int]
f _ [] = []
f x (y:ys)
| even y = y : x : f x ys
| otherwise = y : f x ys
You can also generalize the type signature, and work with an inner function to avoid passing the x each time:
f :: Integral a => a -> [a] -> [a]
f x = go
where go [] = []
go (y:ys)
| even y = y : x : go ys
| otherwise = y : go ys
Another way of looking at this would be using a right fold to insert the desired element after even numbers.
f :: Int -> [Int] -> [Int]
f x lst = foldr (\y i -> if even y then y:x:i else y:i) [] lst
Which we can simplify to:
f :: Int -> [Int] -> [Int]
f x = foldr (\y i -> if even y then y:x:i else y:i) []
Note that without specifying the type, the more general inferred type of f would be:
f :: (Foldable t, Integral a) => a -> t a -> [a]

Haskell dependent, independent variables in lambda function as applied to foldr

Given
> foldr (+) 5 [1,2,3,4]
15
this second version
foldr (\x n -> x + n) 5 [1,2,3,4]
also returns 15. The first thing I don't understand about the second version is how foldr knows which variable is associated with the accumulator-seed 5 and which with the list variable's elements [1,2,3,4]. In the lambda calculus way, x would seem to be the dependent variable and n the independent variable. So if this
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
is foldr and these
:type foldr
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
:t +d foldr
foldr :: (a -> b -> b) -> b -> [a] -> b
its type declarations, can I glean, deduce the answer to "which is dependent and which is independent" from the type declaration itself? It would seem both examples of foldr above must be doing this
(+) 1 ((+) 2 ((+) 3 ((+) 4 ((+) 5 0))))
I simply guessed the second, lambda function version above, but I don't really understand how it works, whereas the first version with (+) breaks down as shown directly above.
Another example would be this
length' = foldr (const (1+)) 0
where, again, const seems to know to "throw out" the incoming list elements and simply increment, starting with the initial accumulator value. This is the same as
length' = foldr (\_ acc -> 1 + acc) 0
where, again, Haskell knows which of foldr's second and third arguments -- accumulator and list -- to treat as the dependent and independent variable, seemingly by magic. But no, I'm sure the answer lies in the type declaration (which I can't decipher, hence, this post), as well as the lore of lambda calculus, of which I'm a beginner.
Update
I've found this
reverse = foldl (flip (:)) []
and then applying to a list
foldl (flip (:)) [] [1,2,3]
foldl (flip (:)) (1:[]) [2,3]
foldl (flip (:)) (2:1:[]) [3]
foldl (flip (:)) (3:2:1:[]) []
. . .
Here it's obvious that the order is "accumulator" and then list, and flip is flipping the first and second variables, then subjecting them to (:). Again, this
reverse = foldl (\acc x -> x : acc) []
foldl (\acc x -> x : acc) [] [1,2,3]
foldl (\acc x -> x : acc) (1:[]) [1,2,3]
. . .
seems also to rely on order, but in the example from further above
length' = foldr (\_ acc -> 1 + acc) 0
foldr (\_ acc -> 1 + acc) 0 [1,2,3]
how does it know 0 is the accumulator and is bound to acc and not the first (ghost) variable? So as I understand (the first five pages of) lambda calculus, any variable that is "lambda'd," e.g., \x is a dependent variable, and all other non-lambda'd variables are independent. Above, the \_ is associated with [1,2,3] and the acc, ostensibly the independent variable, is 0; hence, order is not dictating assignment. It's as if acc was some keyword that when used always binds to the accumulator, while x is always talking about the incoming list members.
Also, what is the "algebra" in the type definition where t a is transformed to [a]? Is this something from category theory? I see
Data.Foldable.toList :: t a -> [a]
in the Foldable definition. Is that all it is?
By "dependent" you most probably mean bound variable.
By "independent" you most probably mean free (i.e. not bound) variable.
There are no free variables in (\x n -> x + n). Both x and n appear to the left of the arrow, ->, so they are named parameters of this lambda function, bound inside its body, to the right of the arrow. Being bound means that each reference to n, say, in the function's body is replaced with the reference to the corresponding argument when this lambda function is indeed applied to its argument(s).
Similarly both _ and acc are bound in (\_ acc -> 1 + acc)'s body. The fact that the wildcard is used here, is immaterial. We could just have written _we_dont_care_ all the same.
The parameters in lambda function definition get "assigned" (also called "bound") the values of the arguments in an application, purely positionally. The first argument will be bound / assigned to the first parameter, the second argument - to the second parameter. Then the lambda function's body will be entered and further reduced according to the rules.
This can be seen a bit differently stating that actually in lambda calculus all functions have only one parameter, and multi-parameter functions are actually nested uni-parameter lambda functions; and that the application is left-associative i.e. nested to the left.
What this actually means is quite simply
(\ x n -> x + n) 5 0
=
(\ x -> (\ n -> x + n)) 5 0
=
((\ x -> (\ n -> x + n)) 5) 0
=
(\ n -> 5 + n) 0
=
5 + 0
As to how Haskell knows which is which from the type signatures, again, the type variables in the functional types are also positional, with first type variable corresponding to the type of the first expected argument, the second type variable to the second expected argument's type, and so on.
It is all purely positional.
Thus, as a matter of purely mechanical and careful substitution, since by the definition of foldr it holds that foldr g 0 [1,2,3] = g 1 (foldr g 0 [2,3]) = ... = g 1 (g 2 (g 3 0)), we have
foldr (\x n -> x + n) 0 [1,2,3]
=
(\x n -> x + n) 1 ( (\x n -> x + n) 2 ( (\x n -> x + n) 3 0 ))
=
(\x -> (\n -> x + n)) 1 ( (\x n -> x + n) 2 ( (\x n -> x + n) 3 0 ))
=
(\n -> 1 + n) ( (\x n -> x + n) 2 ( (\x n -> x + n) 3 0 ))
=
1 + ( (\x n -> x + n) 2 ( (\x n -> x + n) 3 0 ))
=
1 + ( (\x (\n -> x + n)) 2 ( (\x n -> x + n) 3 0 ))
=
1 + (\n -> 2 + n) ( (\x n -> x + n) 3 0 )
=
1 + (2 + (\x n -> x + n) 3 0 )
=
1 + (2 + (\x -> (\n -> x + n)) 3 0 )
=
1 + (2 + (\n -> 3 + n) 0 )
=
1 + (2 + ( 3 + 0))
In other words, there is absolutely no difference between (\x n -> x + n) and (+).
As for that t in foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b, what that means is that given a certain type T a, if instance Foldable T exists, then the type becomes foldr :: (a -> b -> b) -> b -> T a -> b, when it's used with a value of type T a.
One example is Maybe a and thus foldr (g :: a -> b -> b) (z :: b) :: Maybe a -> b.
Another example is [] a and thus foldr (g :: a -> b -> b) (z :: b) :: [a] -> b.
(edit:) So let's focus on lists. What does it mean for a function foo to have that type,
foo :: (a -> b -> b) -> b -> [a] -> b
? It means that it expects an argument of type a -> b -> b, i.e. a function, let's call it g, so that
foo :: (a -> b -> b) -> b -> [a] -> b
g :: a -> b -> b
-------------------------------------
foo g :: b -> [a] -> b
which is itself a function, expecting of some argument z of type b, so that
foo :: (a -> b -> b) -> b -> [a] -> b
g :: a -> b -> b
z :: b
-------------------------------------
foo g z :: [a] -> b
which is itself a function, expecting of some argument xs of type [a], so that
foo :: (a -> b -> b) -> b -> [a] -> b
g :: a -> b -> b
z :: b
xs :: [a]
-------------------------------------
foo g z xs :: b
And what could such function foo g z do, given a list, say, [x] (i.e. x :: a, [x] :: [a])?
foo g z [x] = b where
We need to produce a b value, but how? Well, g :: a -> b -> b produces a function b -> b given an value of type a. Wait, we have that!
f = g x -- f :: b -> b
and what does it help us? Well, we have z :: b, so
b = f z
And what if it's [] we're given? We don't have any as then at all, but we have a b type value, z -- so instead of the above we'd just define
b = z
And what if it's [x,y] we're given? We'll do the same f-building trick, twice:
f1 = g x -- f1 :: b -> b
f2 = g y -- f2 :: b -> b
and to produce b we have many options now: it's z! or maybe, it's f1 z!? or f2 z? But the most general thing we can do, making use of all the data we have access to, is
b = f1 (f2 z)
for a right-fold (...... or,
b = f2 (f1 z)
for a left).
And if we substitute and simplify, we get
foldr g z [] = z
foldr g z [x] = g x z -- = g x (foldr g z [])
foldr g z [x,y] = g x (g y z) -- = g x (foldr g z [y])
foldr g z [x,y,w] = g x (g y (g w z)) -- = g x (foldr g z [y,w])
A pattern emerges.
Etc., etc., etc.
A sidenote: b is a bad naming choice, as is usual in Haskell. r would be much much better -- a mnemonic for "recursive result".
Another mnemonic is the order of g's arguments: a -> r -> r suggests, nay dictates, that a list's element a comes as a first argument; r the recursive result comes second (the Result of Recursively processing the Rest of the input list -- recursively, thus in the same manner); and the overall result is then produced by this "step"-function, g.
And that's the essence of recursion: recursively process self-similar sub-part(s) of the input structure, and complete the processing by a simple single step:
a a
: `g`
[a] r
------------- -------------
[a] r
[a]
a [a]
--------
(x : xs) -> r
xs -> r
----------------------
( x , r ) -> r --- or, equivalently, x -> r -> r
Well, the foldr itself knows this by definition. It was defined in such way that its function argument accepts the accumulator as 2nd argument.
Just like when you write a div x y = ... function you are free to use y as dividend.
Maybe you got confused by the fact that foldr and foldl has swapped arguments in the accumulator funtions?
As Steven Leiva says here, a foldr (1) takes a list and replaces the cons operators (:) with the given function and (2) replaces the last empty list [] with the accumulator-seed, which is what the definition of foldr says it will do
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)
So de-sugared [1,2,3] is
(:) 1 ((:) 2 ((:) 3 []))
and the recursion is in effect replacing the (:) with f, and as we see in foldr f z (x:xs) = f x (foldr f z xs), the z seed value is going along for the ride until the base case where it is substituted for the [], fulfilling (1) and (2) above.
My first confusion was seeing this
foldr (\x n -> x + n) 0 [1,2,3]
and not understanding it would be expanded out, per definition above, to
(\x n -> x + n) 1 ((\x n -> x + n) 2 ((\x n -> x + n) 3 0 ))
Next, due to a weak understanding of how the actual beta reduction would progress, I didn't understand the second-to-third step below
(\x -> (\n -> x + n)) 1 ...
(\n -> 1 + n) ...
1 + ...
That second-to-third step is lambda calculus being bizarre all right, but is at the root of why (+) and (\x n -> x + n) are the same thing. I don't think it's pure lambda calculus addition, but it (verbosely) mimics addition in recursion. I probably need to jump back into lambda calculus to really grasp why (\n -> 1 + n) turns into 1 +
My worse mental block was thinking I was looking at some sort of eager evaluation inside the parentheses first
foldr ((\x n -> x + n) 0 [1,2,3,4])
where the three arguments to foldr would interact first, i.e., 0 would be bound to the x and the list member to the n
(\x n -> x + n) 0 [1,2,3,4]
0 + 1
. . . then I didn't know what to think. Totally wrong-headed, even though, as Will Ness points out above, beta reduction is positional in binding arguments to variables. But, of course, I left out the fact that Haskell currying means we follow the expansion of foldr first.
I still don't fully understand the type definition
foldr :: (a -> b -> b) -> b -> [a] -> b
other than to comment/guess that the first a and the [a] mean a is of the type of the members of the incoming list and that the (a -> b -> b) is a prelim-microcosm of what foldr will do, i.e., it will take an argument of the incoming list's type (in our case the elements of the list?) then another object of type b and produce an object b. So the seed argument is of type b and the whole process will finally produce something of type b, also the given function argument will take an a and ultimately give back an object b which actually might be of type a as well, and in fact is in the above example with integers... IOW, I don't really have a firm grasp of the type definition...

foldr with 4 arguments?

I am struggling to understand why this code taken from the haskell.org exercise page typechecks (and works as a list reversal function):
myReverse :: [a] -> [a]
myReverse xs = foldr (\x fId empty -> fId (x : empty)) id xs []
My first point of confusion is that foldr accepts 3 arguments, not 4 :
foldr :: Foldable t => (a -> b -> b) -> b -> t a -> b
so I am guessing that myReverse is equivalent to:
myReverse xs = foldr ((\x fId empty -> fId (x : empty)) id) xs []
but then this should not work either since in the lambda, x is a list element rather than a function ...
Think of it this way. Every function accepts exactly one argument. It may return another function (that accepts one argument). The thing that looks like a multi-argument call
f a b c
is actually parsed as
((f a) b) c
that is, a chain of single-argument function applications. A function type
f :: a -> b -> c -> d
can be decomposed to
f :: a -> (b -> (c -> d))
i.e. a function returning a function returning a function. We usually regard it as a function of three arguments. But can it accept more than three? Yes, if d happens to be another function type.
This is exactly what happens with your fold example. The function that you pass as the first argument to foldr accepts three arguments, which is exactly the same as accepting two arguments and returning another function. Now the (simplified) type of foldr is
(a -> b -> b) -> b -> [a] -> b
but if you look at the first argument of it, you see it's a function of three arguments. Which is, as we have seen, exactly the same as a function that acceora two arguments and returns a function. So the b happens to be a function type. Since b is also the the return tuoe of foldr when applied to three arguments
foldr (\x fId empty -> fId (x : empty)) id
and it's a function, it can now be applied to another argument
(foldr (\x fId empty -> fId (x : empty)) id xs) []
I let you figure out what b actually is.
First of all the variables naming is atrocious. I always use r for the second argument to a foldr's reducer function, as a mnemonic for the "recursive result". "empty" is too overloaded with meaning; it is better to use some neutral name so it is easier to see what it is without any preconceived notions:
myReverse :: [a] -> [a]
myReverse xs = foldr (\x r n -> r (x : n)) id xs []
By virtue of foldr's definition,
foldr f z (x:xs) === f x (foldr f z xs)
i.e.
myReverse [a,b,c,...,z]
= foldr (\x r n -> r (x : n)) id [a,b,c,...,z] []
= (\x r n -> r (x : n)) a (foldr (\x r n -> r (x : n)) id [b,c,...,z]) []
= (\x r n -> r (x : n))
a
(foldr (\x r n -> r (x : n)) id [b,c,...,z])
[]
= let { x = a
; r = foldr (\x r n -> r (x : n)) id [b,c,...,z]
; n = []
}
in r (x : n)
= foldr (\x r n -> r (x : n)) id [b,c,...,z] (a : [])
= foldr (\x r n -> r (x : n)) id [b,c,...,z] [a]
= ....
= foldr (\x r n -> r (x : n)) id [c,...,z] (b : [a])
= foldr (\x r n -> r (x : n)) id [c,...,z] [b,a]
= ....
= foldr (\x r n -> r (x : n)) id [] [z,...,c,b,a]
= id [z,...,c,b,a]
I hope this illustration makes it clearer what is going on there. The extra argument is expected by the reducer function, which is pushed into action by foldr ... resulting in the operational equivalent of
= foldl (\n x -> (x : n)) [] [a,b,c,...,z]
As it turns out, myReverse implementation is using the equivalence
foldl (flip f) n xs === foldr (\x r -> r . f x) id xs n

How would you declare the types of these functions in Haskell?

So I'm learning about Haskell at the moment, and I came across this question:
The type of a function f is supposed to be a->[a]->a. The
following definitions of f are incorrect because their types are all
different from a->[a]->a:
i. f x xs = xs
ii. f x xs = x+1
iii. f x xs = x ++ xs
iv. f x (y:ys) = y
My answers as I see it are:
i) f :: a -> a -> a
This is because x or xs can be of any value and is not a list as it does not contain the ':' operator.
ii) f :: Int -> a -> Int
This is because the + operator is used on x, meaning x is of type Int.
iii) f :: Eq a => a -> a -> a
The ++ operators are used, therefore in order to concatenate they must be of the same type..?
iv) f :: a -> [a] -> a
f returns an element from the list.
The last one is definitely wrong, because it can't be of type a -> [a] -> a. Are there any others I did wrong, and why? I'm hoping I can fully understand types and how to find out the types of functions.
i) f :: a -> a -> a
f x xs = xs
This is because x or xs can be of any value and is not a list as it does not contain the ':' operator.
True, but it also does not have to be of the same type!
So, it's actually f :: a -> b -> b.
ii) f :: Int -> a -> Int
f x xs = x+1
This is because the + operator is used on x, meaning x is of type Int.
Correct. (Actually, in Haskell we get Num b => b -> a -> b which generalized the Int to any numeric type, but it's not that important.)
iii) f :: Eq a => a -> a -> a
f x xs = x ++ xs
The ++ operators are used, therefore in order to concatenate they must be of the same type..?
True, but they must be lists. Also, Eq is only needed if you use == or something which compares values.
Here, f :: [a] -> [a] -> [a].
iv) f :: a -> [a] -> a
f x (y:ys) = y
f returns an element from the list.
The type of x does not have to be the same. We get f :: b -> [a] -> a.
i. f x xs = xs
(...)
i) f :: a -> a -> a
Although this can be a type signature, you make it too restrictive. The function takes two parameters x and xs. Initially we can reason that x and xs can have different types, so we say that x :: a, and xs :: b. Since the function returns xs, the return type is b as well, so the type is:
f :: a -> b -> b
f x xs = xs
ii. f x xs = x+1
(...)
ii) f :: Int -> a -> Int
Again you make the function too restrictive. Let us again assume that x :: a and xs :: b have different types. We see that we return x + 1 (or in more canonical form (+) x 1. Since (+) has signature (+) :: Num c => c -> c -> c (we here use c since a is already used), and 1 has signature 1 :: Num d => d, we thus see that we call (+) with x and 1, as a result we know that a ~ c (a and c are the same type), and c ~ d, so as a result we obtain the signature:
f :: Num c => c -> b -> c
f x xs = x+1
iii. f x xs = x ++ xs
(...)
iii) f :: Eq a => a -> a -> a
This is wrong: we here see that f has two parameters, x :: a and xs :: b. We see that we return (++) x xs. Since (++) has signature (++) :: [c] -> [c] -> [c], we thus know that a ~ [c] and b ~ [c], so the type is:
f :: [c] -> [c] -> [c]
f x xs = x ++ xs
iv. f x (y:ys) = y
(...)
iv) f :: a -> [a] -> a
This is again too restrictive. Here we see again two parameters: x and (y:ys). We first generate a type a for x :: a, and (y:ys) :: b, since the pattern of the second parameter is (y:ys), this is a list constructor with as parameters (:) :: c -> [c] -> [c]. As a result we can derive that y :: c, and ys :: [c], furthermore the pattern (y:ys) has type [c]. Since the function returns y, we know that the return type is c, so:
f :: a -> [c] -> c
f x (y:ys) = y
Note: you can let Haskell derive the type of the function itself. In GHCi you can use the :t command to query the type of an expression. For example:
Prelude> f x (y:ys) = y
Prelude> :t f
f :: t1 -> [t] -> t

Defining foldl in terms of foldr in Standard ML

The defined code is
fun foldl f e l = let
fun g(x, f'') = fn y => f''(f(x, y))
in foldr g (fn x => x) l e end
I don't understand how this works;
what is the purpose of g(x, f'')?
I also find a similar example in Haskell,
the definition is quite short
myFoldl f z xs = foldr step id xs z
where
step x g a = g (f a x)
Let's dissect the Haskell implementation of myFoldl and then take a look at the ocaml SML code. First, we'll look at some type signatures:
foldr :: (a -> b -> b) -- the step function
-> b -- the initial value of the accumulator
-> [a] -- the list to fold
-> b -- the result
It should be noted that although the foldr function accepts only three arguments we are applying it two four arguments:
foldr step id xs z
However, as you can see the second argument to foldr (i.e. the inital value of the accumulator) is id which is a function of the type x -> x. Therefore, the result is also of the type x -> x. Hence, it accepts four arguments.
Similarly, the step function is now of the type a -> (x -> x) -> x -> x. Hence, it accepts three arguments instead of two. The accumulator is an endofunction (i.e. a function whose domain and codomain is the same).
Endofunctions have a special property, they are composed from left to right instead of from right to left. For example, let's compose a bunch of Int -> Int functions:
inc :: Int -> Int
inc n = n + 1
dbl :: Int -> Int
dbl n = n * 2
The normal way to compose these functions is to use the function composition operator as follows:
incDbl :: Int -> Int
incDbl = inc . dbl
The incDbl function first doubles a number and then increments it. Note that this reads from right to left.
Another way to compose them is to use continuations (denoted by k):
inc' :: (Int -> Int) -> Int -> Int
inc' k n = k (n + 1)
dbl' :: (Int -> Int) -> Int -> Int
dbl' k n = k (n * 2)
Notice that the first argument is a continuation. If we want to recover the original functions then we can do:
inc :: Int -> Int
inc = inc' id
dbl :: Int -> Int
dbl = dbl' id
However, if we want to compose them then we do it as follows:
incDbl' :: (Int -> Int) -> Int -> Int
incDbl' = dbl' . inc'
incDbl :: Int -> Int
incDbl = incDbl' id
Notice that although we are still using the dot operator to compose the functions, it now reads from left to right.
This is the key behind making foldr behave as foldl. We fold the list from right to left but instead of folding it into a value, we fold it into an endofunction which when applied to an initial accumulator value actually folds the list from left to right.
Consider our incDbl function:
incDbl = incDbl' id
= (dbl' . inc') id
= dbl' (inc' id)
Now consider the definition of foldr:
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr _ acc [] = acc
foldr fun acc (y:ys) = fun y (foldr fun acc ys)
In the basis case we simply return the accumulated value. However, in the inductive case we return fun y (foldr fun acc ys). Our step function is defined as follows:
step :: a -> (x -> x) -> x -> x
step x g a = g (f a x)
Here f is the reducer function of foldl and is of the type x -> a -> x. Notice that step x is an endofunction of the type (x -> x) -> x -> x which we know can be composed left to right.
Hence the folding operation (i.e. foldr step id) on a list [y1,y2..yn] looks like:
step y1 (step y2 (... (step yn id)))
-- or
(step y1 . step y2 . {dots} . step yn) id
Each step yx is an endofunction. Hence, this is equivalent to composing the endofunctions from left to right.
When this result is applied to an initial accumulator value then the list folds from left to right. Hence, myFoldl f z xs = foldr step id xs z.
Now consider the foldl function (which is written in Standard ML and not OCaml). It is defined as:
fun foldl f e l = let fun g (x, f'') = fn y => f'' (f (x, y))
in foldr g (fn x => x) l e end
The biggest difference between the foldr functions of Haskell and SML are:
In Haskell the reducer function has the type a -> b -> b.
In SML the reducer function has the type (a, b) -> b.
Both are correct. It's only a matter of preference. In SML instead of passing two separate arguments, you pass one single tuple which contains both arguments.
Now, the similarities:
The id function in Haskell is the anonymous fn x => x function in SML.
The step function in Haskell is the function g in SML which takes a tuple containing the first two arguments.
The step function is Haskell step x g a has been split into two functions in SML g (x, f'') = fn y => f'' (f (x, y)) for more clarity.
If we rewrite the SML function to use the same names as in Haskell then we have:
fun myFoldl f z xs = let step (x, g) = fn a => g (f (a, x))
in foldr step (fn x => x) xs z end
Hence, they are exactly the same function. The expression g (x, f'') simply applies the function g to the tuple (x, f''). Here f'' is a valid identifier.
Intuition
The foldl function traverses the list head to tail while operating elements with an accumulator:
(...(a⊗x1)⊗...⊗xn-1)⊗xn
And you want to define it via a foldr:
x1⊕(x2⊕...⊕(xn⊕e)...)
Rather unintuitive. The trick is that your foldr will not produce a value, but rather a function. The list traversal will operate the elements as to produce a function that, when applied to the accumulator, performs the computation you desire.
Lets see a simple example to illustrate how this works. Consider sum foldl (+) 0 [1,2,3] = ((0+1)+2)+3. We may calculate it via foldr as follows.
foldr ⊕ [1,2,3] id
-> 1⊕(2⊕(3⊕id))
-> 1⊕(2⊕(id.(+3))
-> 1⊕(id.(+3).(+2))
-> (id.(+3).(+2).(+1))
So when we apply this function to 0 we get
(id.(+3).(+2).(+1)) 0
= ((0+1)+2)+3
We began with the identity function and successively changed it as we traversed the list, using ⊕ where,
n ⊕ g = g . (+n)
Using this intuition, it isn't hard to define a sum with an accumulator via foldr. We built the computation for a given list via foldr ⊕ id xs. Then to calculate the sum we applied it to 0, foldr ⊕ id xs 0. So we have,
foldl (+) 0 xs = foldr ⊕ id xs 0
where n ⊕ g = g . (+n)
or equivalently, denoting n ⊕ g in prefix form by (⊕) n g and noting that (⊕) n g a = (g . (+n)) a = g (a+n),
foldl (+) 0 xs = foldr ⊕ id xs 0
where (⊕) n g a = g (a+n)
Note that the ⊕ is your step function, and that you can obtain the generic result you're looking for by substituting a function f for +, and accumulator a for 0.
Next let us show that the above really is correct.
Formal derivation
Moving on to a more formal approach. It is useful, for simplicity, to be aware of the following universal property of foldr.
h [] = e
h (x:xs) = f x (h xs)
iff
h = foldr f e
This means that rather than defining foldr directly, we may instead and more simply define a function h in the form above.
We want to define such an h so that,
h xs a = foldl f a xs
or equivalently,
h xs = \a -> foldl f a xs
So lets determine h. The empty case is simple:
h [] = \a -> foldl f a []
= \a -> a
= id
The non-empty case results in:
h (x:xs) = \a -> foldl f a (x:xs)
= \a -> foldl f (f a x) xs
= \a -> h xs (f a x)
= step x (h xs) where step x g = \a -> g (f a x)
= step x (h xs) where step x g a = g (f a x)
So we conclude that,
h [] = id
h (x:xs) = step x (h xs) where step x g a = g (f a x)
satisfies h xs a = foldl f a xs
And by the universal property above (noting that the f in the universal property formula corresponds to step here, and e to id) we know that h = foldr step id. Therefore,
h = foldr step id
h xs a = foldl f a xs
-----------------------
foldl f a xs = foldr step id xs a
where step x g a = g (f a x)

Resources