Reputation: 262494
In Haskell, I can give too few arguments to a function to get back a curried function:
-- the addition function
Prelude> :t (+)
(+) :: Num a => a -> a -> a
-- curried with its first argument => the increment function
Prelude> :t (+) 1
(+) 1 :: Num a => a -> a
-- supplied with both arguments => the result
Prelude> :t (+) 1 2
(+) 1 2 :: Num a => a
But what do I get when I supply too many arguments?
Prelude> :t (+) 1 2 3
(+) 1 2 3 :: (Num a, Num (a -> t)) => t
What is this, does it have a name, and is it useful for anything?
Upvotes: 0
Views: 443
Reputation: 119857
It's useful to think about it this way. You always give exactly one argument to a function. f a b
is exactly equivalent to (f a) b
.
So (+) 1 2 3
is the same as
(((+) 1) 2) 3
Now we know what ((+) 1) 2
is, it's the same as (+) 1 2
or 1 + 2
which is just 3. So the expression boils down to 3 3
.
How come it's not an error?
Integer literals in Haskell are overloaded. 3
could be of any type, provided this type has a Num
instance. There is nothing illegal to give a Num
instance to a function type either. The type inferencer tells you just that:
(Num a, Num (a -> t)) => t
This can be read as
For any type
a
which has aNum
instance, and any typea->t
which also has aNum
instance, the expression in question has typet
.
Of course in practice such instances are unlikely, but one can in principle define them, and make the expression (+) 1 2 3
evaluate to a well-defined value.
Upvotes: 9
Reputation: 531055
In general, you just get an error, because the result of applying a function to "enough" arguments does not produce a value that can be applied to another value as a function.
> (++) [1] [2] [3]
<interactive>:1:1: error:
• Couldn't match expected type ‘[Integer] -> t’
with actual type ‘[Integer]’
• The function ‘(++)’ is applied to three arguments,
but its type ‘[Integer] -> [Integer] -> [Integer]’ has only two
In the expression: (++) [1] [2] [3]
In an equation for ‘it’: it = (++) [1] [2] [3]
• Relevant bindings include it :: t (bound at <interactive>:1:1)
In the case of (+)
, though, the return value can be of any type that has an instance of Num
. Since (+) 1 2
has type Num a => a
, then if a -> t
also had an instance of Num
, it would be fine to assume that (+) 1 2
could be applied again to a third value. This is a demonstration that type classes are open.
Upvotes: 5