Haskell中的指数

sky*_*ird 84 haskell exponent exponentiation

有人能告诉我为什么Haskell Prelude为取幂定义了两个独立的函数(即^**)吗?我认为类型系统应该消除这种重复.

Prelude> 2^2
4
Prelude> 4**0.5
2.0
Run Code Online (Sandbox Code Playgroud)

Mik*_*kov 124

这样共有三种幂运营商:(^),(^^)(**).^是非负积分求幂,^^是整数求幂,**是浮点求幂:

(^) :: (Num a, Integral b) => a -> b -> a
(^^) :: (Fractional a, Integral b) => a -> b -> a
(**) :: Floating a => a -> a -> a
Run Code Online (Sandbox Code Playgroud)

原因是类型安全:数值运算的结果通常与输入参数具有相同的类型.但是你不能提高Int到浮点功率并获得类型的结果Int.因此类型系统阻止您这样做:(1::Int) ** 0.5产生类型错误.同样的道理(1::Int) ^^ (-1).

另一种方法是:Num关闭类型^(它们不需要有乘法逆),Fractional类型关闭^^,Floating类型关闭**.由于没有Fractional实例Int,你无法将其提升为负功率.

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


aug*_*tss 29

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 **
Run Code Online (Sandbox Code Playgroud)

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

  • _"类型系统不够强大"_论点在2015年3月仍然有效吗? (7认同)
  • 关于这个问题的声明是否仍然可以实现?IIRC,haskell有一个选项,可以严格按第一个参数确定多参数类型类的第二个参数.还有另外一个无法解决的问题吗? (4认同)
  • 您当然不能按照我的建议编写它,但是可能会有一些编码方法。 (3认同)
  • @singular仍然是事实。第一个参数不能确定第二个参数,例如,您希望指数既是Int又是Integer。为了能够具有这三个实例声明,实例解析必须使用回溯,并且没有Haskell编译器实现。 (2认同)
  • @ErikAllik可能对标准的Haskell有用,因为自2010年以来没有新的Haskell报告发布。 (2认同)

Gab*_*abe 10

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

有三个双参数取幂运算:( ^)将任意数字提升为非负整数幂,(^^)将小数提升为任何整数幂,(**)取两个浮点参数.的值x^0x^^0为1对任何x,包括零; 0**y未定义.

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