Question

I was reading the answer to this question: Haskell: difference between . (dot) and $ (dollar sign) And the reply struck me as odd... What does he mean + has no input? And then I tried:

((+) 1)
((+) 1 1)
((+) 1 1 1)

Whoops... sad news. But I'm sure I saw functions that can take seemingly arbitrary or a very large number of arguments to believe that someone had defined them in a way a->b->c...->z. There must be some way to handle it! What I'm looking for is something like &rest or &optional in CL.

Was it helpful?

Solution

Sure, you can define a variadic addition function, with some typeclass hackery:1

{-# LANGUAGE TypeFamilies #-}

class Add r where
    add' :: (Integer -> Integer) -> r

instance Add Integer where
    add' k = k 0

instance (n ~ Integer, Add r) => Add (n -> r) where
    add' k m = add' (\n -> k (m+n))

add :: (Add r) => r
add = add' id

And so:

GHCi> add 1 2 :: Integer
3
GHCi> add 1 2 3 :: Integer
6

The same trick is used by the standard Text.Printf module. It's generally avoided for two reasons: one, the types it gives you can be awkward to work with, and you often have to specify an explicit type signature for your use; two, it's really a hack, and should be used rarely, if at all. printf has to take any number of arguments and be polymorphic, so it can't simply take a list list, but for addition, you could just use sum.

1 The language extension isn't strictly necessary here, but they make the usage easier (without them, you'd have to explicitly specify the type of each argument in the examples I gave, e.g. add (1 :: Integer) (2 :: Integer) :: Integer).

OTHER TIPS

It's a syntactical trade-off: you can't (in general) have both variable arity functions and nice Haskell-style syntax for function application at the same time. This is because it would make many expressions ambiguous.

Suppose you have a function foo that allows an arity of 1 or 2, and consider the following expression:

foo a b

Should the 1 or 2 argument version of foo be used here? No way for the compiler to know, as it could be the 2 argument version but it could equally be the result of the 1 argument version applied to b.

Hence language designers need to make a choice.

  • Haskell opts for nice function application syntax (no parentheses required)
  • Lisp opts for variable arity functions (and adds parentheses to remove the ambiguity)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top