Thilo
Thilo

Reputation: 262494

Giving too many arguments to a function in Haskell

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

Answers (2)

n. m. could be an AI
n. m. could be an AI

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 a Num instance, and any type a->t which also has a Num instance, the expression in question has type t.

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

chepner
chepner

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

Related Questions