Can someone explain me, why do these functions have different number of arguments and behavior, but the same type signature, yet they are both correct?
comp1 :: (a -> b) -> (b -> c) -> a -> c
comp1 f g = g.f
comp2 :: (a -> b) -> (b -> c) -> a -> c
comp2 f g x = g (f x)
also, why does comp2 has
comp2 :: (a -> b) -> (b -> c) -> a -> c
instead of something like
comp2 :: a -> (a 开发者_StackOverflow-> b) -> (b -> c) -> a -> c
?
Thank you.
comp2 f g x = g (f x)
is syntactic sugar for
comp2 = \f -> \g -> \x -> g (f x)
Similarly
comp1 f g = g.f
is sugar for
comp1 = \f -> \g -> g.f
The definition of .
is:
f1 . f2 = \x -> f1 (f2 x) -- Names of arguments have been changed to avoid confusion
So if we insert the definition into the desugared form of comp1
, we get:
comp1 = \f -> \g -> \x -> g (f x)
This is exactly the same as the desugared form of comp2
, so clearly the definitions are equivalent.
comp1 f g = g.f
is written in point-free style (not referring to points, but to values). When you call comp1
, there is implicitly a third parameter being passed to g.f
, which is the composition of the two functions g
and f
: (g.f) x
equals g (f x)
, i.e. g
is passed the result of f x
. No parameter x
exists in comp1
because it's implicitly passed to the function. (You could think of comp1
as a partially applied or curried function if it makes you feel better.)
comp2
's type asks for two functions, one from (a->b)
and another (b->c)
, as well as a parameter of type a
. There is no need to put an a ->
in its signature.
The two functions are really equivalent; one simply uses some Haskell tricks to be more concise.
Currying. A multi-argument function in ML and Haskell, is just syntactic sugar for a one-argument function that returns a function; the function that it returns takes the remaining arguments.
精彩评论