views:

50

answers:

2

This question is related to this http://stackoverflow.com/questions/3116165/function-composition-vs-function-application which answered by antal s-z.

How you can get this ?

map has type (a -> b) -> [a] -> [b]
head has type [a] -> a
map head  has type [[a]] -> [a]

Why the following code has type error for function composition ?

 test :: [Char] -> Bool
 test xs = not . null xs

 getMiddleInitials :: [String] -> [Char]
 getMiddleInitials middleNames = map head . filter (\mn -> not . null mn) middleNames

but this does not have type error

getFirstElements :: [[a]] -> [a]
getFirstElements = map head . filter (not . null)

Is it a must to write a point free function in order to utilize the function composition ? I still not very understand the usage of function composition.

Please help. Thanks.

+4  A: 

That's just because function application x y has higher precedence than composition x . y

 test :: [Char] -> Bool
 test xs = (not . null) xs
 -- #      ^          ^

 getMiddleInitials :: [String] -> [Char]
 getMiddleInitials middleNames = (map head . filter (\mn -> (not . null) mn)) middleNames
 -- #                            ^                          ^          ^    ^
KennyTM
+3  A: 

Your error here is actually really simple. If you remember the last part of my answer to your last question, the . operator has higher precedence than anything except for function application. Thus, consider your example of

test :: [Char] -> Bool
test xs = not . null xs

This is parsed as test xs = not . (null xs). Of course, null xs has type Bool, and you can't compose a boolean, and so you get a type error. Thus, you could make your examples work like so:

test :: [Char] -> Bool
test xs = (not . null) xs

getMiddleInitials :: [String] -> [Char]
getMiddleInitials middleNames =
  (map head . filter (\mn -> (not . null) mn)) middleNames

Of course, writing it this way is unusual, but it would work fine.

And no, there are other uses of function composition besides point-free style. One example is to use function composition for some things (e.g. the argument to map or filter), but specify the rest. For instance, take this contrived example:

rejectMapping :: (a -> Bool) -> (a -> b) -> [a] -> [b]
rejectMapping p f = map f . filter (not . p)

This is partly point-free (not . p, for instance, and we left off the final argument), but partly point-full (the existence of p and f).

Antal S-Z
Not really understand the last part which rejectMapping example.
peterwkc
Which part of it don't you understand? The motivation behind it, what it's supposed to do, or how it works? It only uses things you've already seen, so if you think about it, you should be able to follow it!
Antal S-Z