Haskell的幂


91

谁能告诉我为什么Haskell Prelude定义两个单独的求幂函数(即^**)?我认为类型系统应该消除这种重复。

Prelude> 2^2
4
Prelude> 4**0.5
2.0

Answers:


130

这样共有三种幂运营商:(^)(^^)(**)^是非负整数幂,^^是整数幂,并且**是浮点幂:

(^) :: (Num a, Integral b) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a
(**) :: Floating a => a -> a -> a

原因是类型安全:数字运算的结果通常与输入参数具有相同的类型。但是您不能将an Int提升为浮点数并获得type的结果Int。因此,类型系统阻止您执行此操作:(1::Int) ** 0.5产生类型错误。也是一样(1::Int) ^^ (-1)

另一种说法是:Num类型在^(时不带乘法逆)Fractional封闭^^Floating类型在(时)闭口,类型在(时)闭口**。由于没有的Fractional实例Int,因此您无法将其提升为负数。

理想情况下,的第二个参数^将被静态约束为非负值(当前,1 ^ (-2)抛出运行时异常)。但是在里没有自然数的类型Prelude


31

Haskell的类型系统功能不足,无法将三个幂运算符表示为一个。您真正想要的是这样的东西:

class Exp a b where (^) :: a -> b -> a
instance (Num a,        Integral b) => Exp a b where ... -- current ^
instance (Fractional a, Integral b) => Exp a b where ... -- current ^^
instance (Floating a,   Floating b) => Exp a b where ... -- current **

即使您打开了多参数类型类扩展名,这也实际上不起作用,因为实例选择需要比Haskell当前允许的更聪明。


4
关于此问题无法实现的说法是否仍然正确?在IIRC中,haskell有一个选项,可以由第一个参数严格确定多参数类型类的第二个参数。除此之外还有其他无法解决的问题吗?
RussellStewart

2
@singular仍然是事实。第一个参数不能确定第二个参数,例如,您希望指数为IntInteger。为了能够具有这三个实例声明,实例解析必须使用回溯,并且没有Haskell编译器实现。
2014

7
到2015年3月,“类型系统不够强大”的论点是否仍然成立?
Erik Kaplun'3

3
您当然不能按照我的建议编写它,但是可能会有一些编码方法。
2015

2
@ErikAllik可能对标准的Haskell有用,因为自2010
Martin Capodici 2015年

10

它没有定义两个运算符-它定义了三个!从报告中:

共有三个三参数幂运算:( ^)将任何数均提高为非负整数幂,(^^)将小数提高至任何整数幂,并且(**)接受两个浮点参数。的值x^0x^^0为1对任何x,包括零; 0**y未定义。

这意味着存在三种不同的算法,其中两种给出精确的结果(^^^),而**给出近似的结果。通过选择要使用的运算符,可以选择要调用的算法。


4

^要求其第二个参数为Integral。如果我没记错的话,如果您知道自己使用的是整数指数,则实现会更加高效。另外,如果您想要类似的东西2 ^ (1.234),即使您的底数是2的整数,您的结果显然也将是分数。您有更多选择,以便可以更严格地控​​制要输入和输出幂函数的类型。

Haskell的类型系统与其他类型系统(例如C,Python或Lisp)的目标不同。鸭子打字(几乎)与Haskell思维方式相反。


4
我并不完全同意Haskell类型的思维方式与鸭子类型相反。Haskell类型类非常类似于鸭子类型。 class Duck a where quack :: a -> Quack定义我们对鸭子的期望,然后每个实例都指定一些行为类似于鸭子的行为。
2011年

9
@augustss,我知道你来自哪里。但是,鸭子打字背后的非正式座右铭是“如果它看起来像鸭子,像鸭子一样行动,而像鸭子一样嘎嘎叫,那就是鸭子。” 在Haskell中,除非声明为的实例,否则它不是鸭子Duck
丹·伯顿

1
没错,但这就是我对Haskell的期望。您可以制作任何想要的鸭子,但您必须明确。我们不想把我们不想要的东西弄成鸭子。
2011

Haskell的处事方式与鸭子的打字方式之间存在更具体的区别。是的,您可以给任何类型的Duck类,但它不是Duck。当然,它可以发出嘎嘎声,但是不管它是什么类型,它仍然是具体的。您仍然没有鸭子清单。接受鸭子列表并混合和匹配各种类型的鸭子的功能将不起作用。在这方面,Haskell不允许您仅说“如果像鸭子一样发出嘎嘎声,那就是鸭子。” 在Haskell中,所有鸭子都必须是同一类型的Quacker。这与鸭子的确有很大的不同。
mmachenry '02

您可以有混合鸭的列表,但是需要扩展“存在定量”。
Bolpat
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.