简体   繁体   中英

Overloading Haskell functions to have different number of arguments

Is it possible to have two functions of the same name have a different number of arguments in Haskell? This is what I want to do:

inc = (+) 1

inc x = (+) x

I want to be able to call my increment function with no arguments which defaults to incrementing by 1, or with an argument and have it increment by x.

The I can do either of the following, for example:

map(inc)[1,2,3] --results in [2,3,4]

map(inc 2)[1,2,3] -- results in [3,4,5]

First, the simple alternative is to just take a Maybe for this kind of “default argument”:

inc :: Num a => Maybe a -> a -> a
inc Nothing x = 1 + x
inc (Just i) x = i + x

Otherwise, yes it's possible, but it's probably not worthwhile. The technique is to make a typeclass with instances for a concrete type (the result of your operation) and functions (to accept more arguments).

We introduce the class of types that can serve as the result of an increment:

class Inc i where
  inc :: Integer -> i

If the caller demands an integer, we increment by one:

instance Inc Integer where
  inc = (+) 1

If the caller demands a function returning an integer, we increment by the argument of that function:

instance (Integral a) => Inc (a -> Integer) where
  inc x = (+) x . toInteger

Now these both work:

map inc [1, 2, 3]
map (inc 2) [1, 2, 3] :: [Integer]

But the type annotation is required unless the result is constrained to [Integer] by something that uses the result. And type inference gets still worse if you try to use a generic type such as Num a => a instead of the concrete Integer , or if you make it accept any number of arguments by replacing the instance for (Integral a) => Inc (a -> Integer) with one for (Integral a, Inc i) => Inc (a -> i) . On the other hand, you can just as well add instances for other concrete types such as Int and Double .

I suppose my counter-question is: what problem are you actually trying to solve?

No, it's not possible. In Haskell, the most recent definition of a function has precedence. So if you defined both versions of inc:

inc = (+) 1
inc x = (+) x

Then the second definition would shadow the first definition. This means that if you call "inc", the second definition will now be used.

However, you can still accomplish what you want with partial application. If you make your 2 calls curried it will have the same effect. Like so:

map (inc 1) [1,2,3]

returns [2,3,4]

map (inc 2) [1,2,3]

returns [3,4,5]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM