简体   繁体   English

重载Haskell函数以具有不同数量的参数

[英]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? 是否有可能在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. 我想能够调用我的增量函数,没有参数,默认增加1,或者使用参数,并使其增加x。

The I can do either of the following, for example: 我可以做以下任何一种,例如:

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

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

First, the simple alternative is to just take a Maybe for this kind of “default argument”: 首先,简单的替代方法就是为这种“默认参数”选择一个Maybe

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. 但是类型注释是必需的,除非结果被使用结果的东西约束为[Integer] 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) . 如果您尝试使用泛型类型(如Num a => a而不是具体的Integer ,或者如果通过替换(Integral a) => Inc (a -> Integer)的实例来接受任意数量的参数,则类型推断会变得更糟。 (Integral a) => Inc (a -> Integer) ,其中一个用于(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 . 另一方面,您也可以为其他具体类型添加实例,例如IntDouble

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. 在Haskell中,函数的最新定义具有优先权。 So if you defined both versions of inc: 所以如果你定义了两个版本的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. 这意味着如果您调用“inc”,现在将使用第二个定义。

However, you can still accomplish what you want with partial application. 但是,您仍然可以通过部分应用程序完成所需的操作。 If you make your 2 calls curried it will have the same effect. 如果你使你的2个电话咖喱,它将具有相同的效果。 Like so: 像这样:

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

returns [2,3,4] 返回[2,3,4]

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

returns [3,4,5] 返回[3,4,5]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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