Reputation: 819
After playing around with haskell a bit I stumbled over this function:
Prelude Data.Maclaurin> :t ((+) . ($) . (+))
((+) . ($) . (+)) :: (Num a) => a -> (a -> a) -> a -> a
(Data.Maclaurin is exported by the package vector-space.) So it takes a Num, a function, another Num and ultimately returns a Num. What magic makes the following work?
Prelude Data.Maclaurin> ((+) . ($) . (+)) 1 2 3
6
2 is obviously not a function (a->a) or did I miss out on something?
Upvotes: 6
Views: 349
Reputation: 56019
You have good reason to be confused. Using the Data.NumInstances
module in GHC (which is loaded by Data.Maclaurin
) it is possible to coerce a Num
to a constant function.
Prelude Data.NumInstances> :t (2 :: (Num a) => a -> a)
(2 :: (Num a) => a -> a) :: (Num a) => a -> a
Prelude Data.NumInstances> (2 :: (Num a) => a -> a) 0
2
Prelude Data.NumInstances> (2 :: (Num a) => a -> a) 1000
2
The evaluation of the expression is, essentially,
((+) . ($) . (+)) 1 2 3 = ((+) . ($) . (1+)) 2 3
= ((+) (1+)) 2 3
-- (+) is defined for functions that return a Num
= ((+) (1+) (\_ -> 2)) 3
= ((+2) . (1+)) 3
= 6
Upvotes: 1
Reputation: 229894
The Data.NumInstances
module of the same package defines a Num
instance for functions that return numbers:
instance Num b => Num (a->b) where
(+) = liftA2 (+)
(*) = liftA2 (*)
fromInteger = pure . fromInteger
...
In Haskell an integer literal like 2
is generic so that it can represent a number for any instance of Num
:
Prelude> :t 2
2 :: (Num t) => t
To convert it to an actual number of the type required in a specific context, fromInteger
from the Num
class is called.
Since the helper module mentioned above defines an instance of Num
for functions, 2
can now be converted to a function with the fromInteger
method specified there.
So ghci calls fromInteger 2
to get the function required as the second parameter of the construct in the question. The whole expression then happens to evaluate to 6
.
Upvotes: 16