Haskell: foldl via foldr (part III)

As I thought about last night’s post, I was bothered by how confusing it seemed and I finally decided that the reason is that I never directly addressed what was happening.  Yes, I provided an expansion and mentioned the idea of partial function invocation but I never really generalized this idea.  So today seems as good a time as any…

In Haskell, when we talk about partial function execution or “currying” we’re referring to the idea that a function with two or more parameters can receive some of it’s parameters now and others later.  Take a look at the following function declaration (the declaration is the first line, the definition is the second line):

myFunc :: (Num a) => a -> a -> a

myFunc a b = a * b

What this function declaration tells us is that myFunc takes a parameter of type a and a second parameter of type a and returns a result of type a.  But there is more going on here.  Look at how we define the final returns: ->  Why would we use this same symbol between the first and second parameters?  The reason is that the definition is telling us something very deep about how Haskell approaches functions – what it’s really saying is that myFunc accepts a parameter of type a and returns a result that is a function.  This resulting function accepts a parameter of type a and returns a result of type a.

Let’s rewrite the function declaration to perhaps make this point a bit more clear:

myFunc :: (Num a) => a -> (a -> a)

myFunc a b = a * b

we could “curry” or partially execute this function with the following expression:

(myFunc 7)

This expression yields a function that will accept any value and multiply it by 7 – all it needs is that second parameter.  Now don’t be fooled into thinking this is a simple parlor trick and that all we’ve really done is put parentheses in an odd place.  Haskell allows us to pass this “curried” function as a parameter to any function that accepts a function argument that is required to accept a Num and return a Num.

We can do the same thing with the built in * function:

((*) 7)

Placing the * operator in parentheses like this simply allows us to treat it like a ‘normal’ function with two following parameters.  In our expression, we provide it with a value of 7 for the first of these two parameters.  When we later use this function by providing it with a Num for its second parameter, it will return that value multiplied by 7.

Again, this isn’t just a shell game – this is how work gets done in Haskell.  Consider the map function which takes a function and applies it to every member of a list to generate a new list.  The function that it accepts as a parameter is required to consume one parameter and return one result.  If we wanted to use map to multiply ever member of a list containing [1,2,3] by 7 then we could simply say:

map ((*) 7) [1,2,3]

this should give us the result [7, 14, 21] (and, in fact, if we try this out in ghci, this is exactly the result that we get).

Now sure we could have written a function that took a number and multiplied it by seven and then passed that function to map but, for a one-off application, sometimes it’s more straightforward to implement it directly like this.  And, yes, this example is trivial but it highlights the capabilities that come from Haskell’s partial execution feature.