Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Confusion about function composition in Haskell

Consider following function definition in ghci.

let myF = sin . cos . sum 

where, . stands for composition of two function (right associative). This I can call

myF [3.14, 3.14]

and it gives me desired result. Apparently, it passes list [3.14, 3.14] to function 'sum' and its 'result' is passed to cos and so on and on. However, if I do this in interpreter

let myF y = sin . cos . sum y 

or

let myF y = sin . cos (sum y) 

then I run into troubles. Modifying this into following gives me desired result.

let myF y = sin . cos $ sum y 

or

let myF y = sin . cos . sum $ y 

The type of (.) suggests that there should not be a problem with following form since 'sum y' is also a function (isn't it? After-all everything is a function in Haskell?)

let myF y = sin . cos . sum y -- this should work?

What is more interesting that I can make it work with two (or many) arguments (think of passing list [3.14, 3.14] as two arguments x and y), I have to write the following

let (myF x) y = (sin . cos . (+ x)) y 
myF 3.14 3.14 -- it works! 
let myF = sin . cos . (+) 
myF 3.14 3.14 -- -- Doesn't work!

There is some discussion on HaskellWiki regarding this form which they call 'PointFree' form http://www.haskell.org/haskellwiki/Pointfree . By reading this article, I am suspecting that this form is different from composition of two lambda expressions. I am getting confused when I try to draw a line separating both of these styles.

like image 558
Dilawar Avatar asked Aug 02 '11 13:08

Dilawar


People also ask

What is the difference between function and composition?

In Maths, the composition of a function is an operation where two functions say f and g generate a new function say h in such a way that h(x) = g(f(x)). It means here function g is applied to the function of x. So, basically, a function is applied to the result of another function.

What is function composition in Haskell?

Composing functions is a common and useful way to create new functions in Haskell. Haskell composition is based on the idea of function composition in mathematics. In mathematics, if you have two functions f(x) and g(x), you compute their composition as f(g(x)). The expression f(g(x)) first calls g and then calls f.

What does == mean in Haskell?

The == is an operator for comparing if two things are equal. It is quite normal haskell function with type "Eq a => a -> a -> Bool". The type tells that it works on every type of a value that implements Eq typeclass, so it is kind of overloaded.

How are functions defined in Haskell?

The most basic way of defining a function in Haskell is to ``declare'' what it does. For example, we can write: double :: Int -> Int double n = 2*n. Here, the first line specifies the type of the function and the second line tells us how the output of double depends on its input.


3 Answers

Let's look at the types. For sin and cos we have:

cos, sin :: Floating a => a -> a

For sum:

sum :: Num a => [a] -> a

Now, sum y turns that into a

sum y :: Num a => a

which is a value, not a function (you could name it a function with no arguments but this is very tricky and you also need to name () -> a functions - there was a discussion somewhere about this but I cannot find the link now - Conal spoke about it).

Anyway, trying cos . sum y won't work because . expects both sides to have types a -> b and b -> c (signature is (b -> c) -> (a -> b) -> (a -> c)) and sum y cannot be written in this style. That's why you need to include parentheses or $.

As for point-free style, the simples translation recipe is this:

  • take you function and move the last argument of function to the end of the expression separated by a function application. For example, in case of mysum x y = x + y we have y at the end but we cannot remove it right now. Instead, rewriting as mysum x y = (x +) y it works.
  • remove said argument. In our case mysum x = (x +)
  • repeat until you have no more arguments. Here mysum = (+)

(I chose a simple example, for more convoluted cases you'll have to use flip and others)

like image 153
Mihai Maruseac Avatar answered Oct 13 '22 20:10

Mihai Maruseac


No, sum y is not a function. It's a number, just like sum [1, 2, 3] is. It therefore makes complete sense that you cannot use the function composition operator (.) with it.

Not everything in Haskell are functions.

like image 7
hammar Avatar answered Oct 13 '22 20:10

hammar


The obligatory cryptic answer is this: (space) binds more tightly than .

Most whitespace in Haskell can be thought of as a very high-fixity $ (the "apply" function). w x . y z is basically the same as (w $ x) . (y $ z)

When you are first learning about $ and . you should also make sure you learn about (space) as well, and make sure you understand how the language semantics implicitly parenthesize things in ways that may not (at first blush) appear intuitive.

like image 4
Dan Burton Avatar answered Oct 13 '22 19:10

Dan Burton