In ghci,
:t ((+).(+))
> ((+).(+)) :: (Num (a -> a), Num a) => a -> (a -> a) -> a -> a
but what is this thing? Can any one give me an example of the use of this please?
How can one composite 2 functions that take 2 parameters each?
for example, how does (map.map) :: (a -> b) -> [[a]] -> [[b]]
work?
(^.^)
(-.-)
(+.+)
(can't help making funny faces out of it. PS: I thought it means to tell the compiler how you feel today)
(->) is often called the "function arrow" or "function type constructor", and while it does have some special syntax, there's not that much special about it. It's essentially an infix type operator. Give it two types, and it gives you the type of functions between those types.
Functions can also be passed as arguments or returned (as we have seen). Their types are given in the type signature. *Main> :t map map :: (a -> b) -> [a] -> [b] *Main> :t filter filter :: (a -> Bool) -> [a] -> [a] flip_args :: (a -> b -> c) -> b -> a -> c flip_args f x y = f y x.
in goes along with let to name one or more local expressions in a pure function.
Haskell provides special syntax to support infix notation. An operator is a function that can be applied using infix syntax (Section 3.4), or partially applied using a section (Section 3.5).
Num (a -> a)
(or e.g. Eq (a -> a)
) is basically an indicator for code that doesn't make any sense1, but the compiler nevertheless deduces a (nonsensical) type signature. Usually it turns up when you've forgotten to apply a function to some argument. In this case, obviously (+)
needs a "plain number" argument to become a "simple function" to which you can post-compose another such function.
However, (a -> a)
is sure enough a valid type of functions that you can also pass on, just not as numbers. For instance, map . (+)
is a perfectly good combination:
Prelude> :t map . (+)
map . (+) :: Num b => b -> [b] -> [b]
Prelude> zipWith (map . (+)) [10,20,30] [[1,2],[3,4]]
[[11,12],[23,24]]
because map
actually expects a function as its first argument. Similarly,
Prelude> zipWith (map . map) [(+10),(+20),(+30)] [[[1,2],[3,4]],[[5,6]]]
[[[11,12],[13,14]],[[25,26]]]
Here, the right map
takes a simple function (like numerical increment) and returns the corresponding list-map function. That function is then fed to the left map
resulting in a function that maps nested lists.
1Actually, you can force it to make sense by defining
instance (Num a) => Num (b -> a) where
fromInteger x = const $ fromInteger x
f + g = \x -> f x + g x
Personally, I'm not a fan of this. It confusing, for instance let a = 3 in 4 a
produces 4
when most people would expect multiplication to 12
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With