foo = foldl $ flip ($)
This piece of Haskell code lies on my homepage. I no longer program in Haskell, but I can still figure out what this does (though I did have to reïnstall ghc to check).
foo = foldl $ flip ($) is just an obtuse way of saying foo = foldl (flip ($)). Now
foldl's signature is:
foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b
Or, more legibly, it takes:
- A function that takes two arguments of type
banda, then returns something of typeb. - A "seed value" of type
b. - A foldable thing
tofas. This can be, for instance, a list.
Now typing
foldl (+) 44 [5, 8, 3, 5]
into ghci outputs 65 – that is, ((((44 + 5) + 8) + 3) + 5).
But in the code example on my homepage, foldl gets passed in too few arguments. That's perfectly legal,
since technically speaking, all functions take only one parameter. In our case, the other two arguments to
foldl can be passed into foo to get the value we want. Let's rewrite the definition to
include explicit parameters:
foo seed entries = foldl (flip ($)) seed entries
And speaking of which, let's rewrite the first argument passed to foldl. $ is an operator
such that f $ x = f x (and ($) is just Haskell's way of expressing that operator as a
function). flip's signature is (a -> b -> c) -> b -> a -> c, and you can think of it as
taking three parameters, but here it's more useful to think of it as taking a function with two parameters and
returning another function that takes in those parameters in the other order.
foo seed entries = foldl (\x f -> f x) seed entries
Here, we can see that if seed has a type of b, then (\x f -> f x) takes in
two arguments of b and b -> c, respectively, and spits out a c. Because of the
signature of foldl, b and c have to refer to the same type. Then a
in the signature shown earlier is b -> b. seed is also a b, and
entries is some foldable thing (let's go with lists for now) of functions b -> b. You can
verify this in ghci.
So what does this code do? The function returns the result from applying each element of entries
successively on seed, so, for instance, foo x [f1, f2, f3] = f3 (f2 (f1 x)). For a concrete
example:
foo 5.2 [\a -> sqrt a, \a -> 35 + a, \a -> cos (2.6 * a)] = (\a -> cos (2.6 * a)) ((\a -> 35 + a) ((\a -> sqrt a) 5.2)) = (\a -> cos (2.6 * a)) ((\a -> 35 + a) (sqrt 5.2)) = (\a -> cos (2.6 * a)) (35 + (sqrt 5.2)) = cos (2.6 * (35 + (sqrt 5.2))) = -0.8958481640418573
I hate Haskell.