Question

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?

Was it helpful?

Solution

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.

OTHER TIPS

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top