Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overloading Haskell functions to have different number of arguments

Tags:

haskell

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]

like image 697
A. Dumais Avatar asked Feb 02 '26 15:02

A. Dumais


2 Answers

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?

like image 98
Jon Purdy Avatar answered Feb 05 '26 07:02

Jon Purdy


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]

like image 38
fileyfood500 Avatar answered Feb 05 '26 07:02

fileyfood500



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!