Online Book Reader

Home Category

Learn You a Haskell for Great Good! - Miran Lipovaca [37]

By Root 428 0
same as ((f a) b) c), while function application with $ is right-associative.

So how does this help us? Most of the time, it’s a convenience function that lets us write fewer parentheses. For example, consider the expression sum (map sqrt [1..130]). Because $ has such a low precedence, we can rewrite that expression as sum $ map sqrt [1..130]. When a $ is encountered, the expression on its right is applied as the parameter to the function on its left.

How about sqrt 3 + 4 + 9? This adds together 9, 4, and the square root of 3. However, if we wanted the square root of 3 + 4 + 9, we would need to write sqrt (3 + 4 + 9). With $, we can also write this as sqrt $ 3 + 4 + 9. You can imagine $ as almost being the equivalent of writing an opening parenthesis and then writing a closing parenthesis on the far right side of the expression.

Let’s look at another example:

ghci> sum (filter (> 10) (map (*2) [2..10]))

80

Whoa, that’s a lot of parentheses! It looks kind of ugly. Here, (*2) is mapped onto [2..10], then we filter the resulting list to keep only those numbers that are larger than 10, and finally those numbers are added together.

We can use the $ function to rewrite our previous example and make it a little easier on the eyes:

ghci> sum $ filter (> 10) (map (*2) [2..10])

80

The $ function is right-associative, meaning that something like f $ g $ x is equivalent to f $ (g $ x). With that in mind, the preceding example can once again be rewritten as follows:

ghci> sum $ filter (> 10) $ map (*2) [2..10]

80

Apart from getting rid of parentheses, $ lets us treat function application like just another function. This allows us to, for instance, map function application over a list of functions, like this:

ghci> map ($ 3) [(4+), (10*), (^2), sqrt]

[7.0,30.0,9.0,1.7320508075688772]

Here, the function ($ 3) gets mapped over the list. If you think about what the ($ 3) function does, you’ll see that it takes a function and then applies that function to 3. So every function in the list gets applied to 3, which is evident in the result.

Function Composition

In mathematics, function composition is defined like this: (f º g)(x) = f(g(x)). This means that composing two functions is the equivalent of calling one function with some value and then calling another function with the result of the first function.

In Haskell, function composition is pretty much the same thing. We do function composition with the . function, which is defined like this:

(.) :: (b -> c) -> (a -> b) -> a -> c

f . g = \x -> f (g x)

Notice the type declaration. f must take as its parameter a value that has the same type as g’s return value. So the resulting function takes a parameter of the same type that g takes and returns a value of the same type that f returns. For example, the expression negate . (* 3) returns a function that takes a number, multiplies it by 3, and then negates it.

One use for function composition is making functions on the fly to pass to other functions. Sure, we can use lambdas for that, but many times, function composition is clearer and more concise.

For example, say we have a list of numbers and we want to turn them all into negative numbers. One way to do that would be to get each number’s absolute value and then negate it, like so:

ghci> map (\x -> negate (abs x)) [5,-3,-6,7,-3,2,-19,24]

[-5,-3,-6,-7,-3,-2,-19,-24]

Notice the lambda and how it looks like the result of function composition. Using function composition, we can rewrite that as follows:

ghci> map (negate . abs) [5,-3,-6,7,-3,2,-19,24]

[-5,-3,-6,-7,-3,-2,-19,-24]

Fabulous! Function composition is right-associative, so we can compose many functions at a time. The expression f (g (z x)) is equivalent to (f . g . z) x. With that in mind, we can turn something messy, like this:

ghci> map (\xs -> negate (sum (tail xs))) [[1..5],[3..6],[1..7]]

[-14,-15,-27]

into something much cleaner, like this:

ghci> map (negate . sum . tail) [[1..5],[3..6],[1..7]]

[-14,-15,-27]

negate . sum . tail is a function that takes a list, applies the tail function to

Return Main Page Previous Page Next Page

®Online Book Reader