Confusion about functional composition in Haskell

Consider the following function definition in ghci.

let myF = sin . cos . sum 

Where,. means a composition of two functions (right associative). I can call it

 myF [3.14, 3.14] 

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

 let myF y = sin . cos . sum y 

or

 let myF y = sin . cos (sum y) 

then I run into problems. Changing this in the following gives me the desired result.

 let myF y = sin . cos $ sum y 

or

 let myF y = sin . cos . sum $ y 

The type (.) Assumes that there should be no problem with the following form, since "sum y" is also a function (isn't it? After all, is this all a function in Haskell?)

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

More interestingly, I can get it to work with two (or many) arguments (think of passing the 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 the "PointFree" form http://www.haskell.org/haskellwiki/Pointfree . After reading this article, I suspect that this form is different from the composition of two lambda expressions. I get confused when I try to draw a line separating both of these styles.

+4
source share
3 answers

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 it into

 sum y :: Num a => a 

which is a value, not a function (you could call it a function without arguments, but it is very complicated, and you also need to call () -> a functions - , it was discussed somewhere, but I can not find the link - Conal talked about it.)

In any case, try cos . sum y cos . sum y will not work because . expects both sides to have types a -> b and b -> c (signature (b -> c) -> (a -> b) -> (a -> c) ) and sum y cannot be written to this style. This is why you need to include parentheses or $ .

As for the dotless style, the character translation recipe is as follows:

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

(I chose a simple example, for more complicated cases you will have to use flip and others)

+9
source

No, sum y not a function. This number, like sum [1, 2, 3] . Therefore, it is understandable that you cannot use the function layout operator (.) With it.

Not everything in Haskell is a function.

+6
source

The required cryptic answer is: (space) is associated more closely than .

Most of the spaces in Haskell can be thought of as a very high $ commit (the "apply" function). wx . yz wx . yz basically matches (w $ x) . (y $ z) (w $ x) . (y $ z)

When you first learn about $ and . You should also make sure that you find out about (space), and also make sure that you understand how the semantics of the language implicitly bracket the lines so (blush first) seems intuitive.

+3
source

All Articles