美好的一天.我是Haskell的新手.关于声明和实例化一些自定义类,有一点我不清楚.
Integralhaskell 有一个标准类.根据hackage,Integral声明强制方法quot :: a -> a -> a.所以这意味着该类的每个实例都应该有这个方法实现,对吗?
我们可以使用Integral作为参数来声明一些函数,例如:
proba :: (Integral a) => a -> a -> a
proba x y = x `quot` y
Run Code Online (Sandbox Code Playgroud)
到现在为止还挺好
class Proba a where
proba :: a -> a -> a
Run Code Online (Sandbox Code Playgroud)
我可以实现这样的Int或Integer(或其他数据类型)实例:
instance Proba Integer where
proba x y = x `quot` y
instance Proba Int where
proba x y = x `quot` y
Run Code Online (Sandbox Code Playgroud)
但我不想.我希望每个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'
Run Code Online (Sandbox Code Playgroud)
好吧,它似乎要求我提供不同的类型变量而不是类.但为什么?!为什么只是在Integral这里就不够了?既然quot是为每一个声明的Integral,那么这个实例应该对每一个都有效Integral,不是吗?
也许有办法达到同样的效果?
正如错误消息所示,您可以使用FlexibleInstances(一个相当常见和安全的扩展)来允许此行为,但您还需要UndecidableInstances:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
class Proba a where
proba :: a -> a -> a
instance Integral a => Proba a where
proba = quot
Run Code Online (Sandbox Code Playgroud)
默认情况下不启用它的原因是因为它特别是GHC扩展,并且它不是Haskell98规范的一部分.您会发现有很多语言扩展非常有用且使用安全,而且通常只需要在特定模块中启用它们.不要只问"为什么不是这个默认值",而是要问"我什么时候不想让它成为默认值?".
在没有扩展的情况下实现此方法的另一种方法是直接将类型类编码为数据类型:
data Proba a = Proba
{ proba :: a -> a -> a
}
integralProba :: Integral a => Proba a
integralProba = Proba quot
Run Code Online (Sandbox Code Playgroud)
然后你可以把它传递给
foldProba :: Proba a -> a -> [a] -> a
foldProba p = foldr (proba p)
Run Code Online (Sandbox Code Playgroud)
然后,如果你有foldProba integralProba,那么它会自动将类型约束为Integral a => a -> [a] -> a.
| 归档时间: |
|
| 查看次数: |
1023 次 |
| 最近记录: |