美好的一天 . 我是Haskell的新手 . 关于声明和实例化一些自定义类,有一件事我不清楚 .
-
haskell中有一个标准类
Integral
. 根据hackage,Integral
声明了强制方法quot :: a -> a -> a
. 所以这意味着该类的每个实例都应该具有此方法实现,对吧? -
我们可以使用Integral作为参数声明一些函数,如:
proba :: (Integral a) => a -> a -> a
proba x y = x `quot` y
到现在为止还挺好
- 现在让我们声明我们自己的类Proba:
class Proba a where
proba :: a -> a -> a
我可以实现这样的Int或Integer(或其他数据类型)实例:
instance Proba Integer where
proba x y = x `quot` y
instance Proba Int where
proba x y = x `quot` y
但我不想 . I want one instance for every Integral. 但是当我尝试这样做时,我收到一个错误:
instance (Integral a) => Proba a where
proba x y = x `quot` y
Illegal instance declaration for `Proba a'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use FlexibleInstances if you want to disable this.)
In the instance declaration for `Proba a'
好吧,似乎它要求我提供不同的类型变量而不是类 . 但为什么?!为什么仅仅在这里拥有一个_1044901就不够了?由于 quot
是为每个 Integral
声明的,因此该实例应该对每个_1044904都有效,不是吗?
也许有办法达到同样的效果?
1 回答
如错误消息所示,您可以使用
FlexibleInstances
(一种相当常见且安全的扩展名)来允许此行为,但您还需要UndecidableInstances
:默认情况下未启用此功能的原因是因为它特别是GHC扩展,并且它不是Haskell98规范的一部分 . 您会发现有很多语言扩展非常有用且使用安全,而且通常只需要在特定模块中启用它们 . 不要只问“为什么不是这个默认值”,而是要问“我什么时候不想让它成为默认值?” .
在没有扩展的情况下实现此方法的另一种方法是直接将类型类编码为数据类型:
然后你可以把它传递给
然后,如果你有
foldProba integralProba
,那么它会自动将类型约束为Integral a => a -> [a] -> a
.