Haskell Type Error From Function Application to Function Composition
-
30-09-2019 - |
Pergunta
This question is related to this 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.
Solução
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
).
Outras dicas
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
-- # ^ ^ ^ ^