谁能告诉我为什么Haskell Prelude定义两个单独的求幂函数(即^和**)?我认为类型系统应该消除这种重复。
Prelude> 2^2
4
Prelude> 4**0.5
2.0
Answers:
这样共有三种幂运营商:(^),(^^)和(**)。^是非负整数幂,^^是整数幂,并且**是浮点幂:
(^) :: (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。
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当前允许的更聪明。
Int和Integer。为了能够具有这三个实例声明,实例解析必须使用回溯,并且没有Haskell编译器实现。
^要求其第二个参数为Integral。如果我没记错的话,如果您知道自己使用的是整数指数,则实现会更加高效。另外,如果您想要类似的东西2 ^ (1.234),即使您的底数是2的整数,您的结果显然也将是分数。您有更多选择,以便可以更严格地控制要输入和输出幂函数的类型。
Haskell的类型系统与其他类型系统(例如C,Python或Lisp)的目标不同。鸭子打字(几乎)与Haskell思维方式相反。
class Duck a where quack :: a -> Quack定义我们对鸭子的期望,然后每个实例都指定一些行为类似于鸭子的行为。
Duck。