Haskell:具有类类型参数的类实例

时间:2014-09-10 15:01:29

标签: haskell

美好的一天。我是Haskell的新手。关于声明和实例化一些自定义类,有一件事我不清楚。

  1. haskell中有一个标准类Integral。根据hackage,Integral声明了强制方法quot :: a -> a -> a。所以这意味着该类的每个实例都应该有这个方法实现,对吧?

  2. 我们可以使用Integral作为参数来声明一些函数,例如:

  3. proba :: (Integral a) => a -> a -> a
    proba x y = x `quot` y
    

    到目前为止一切顺利

    1. 现在让我们宣布我们自己的课程Proba:
    2. 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
      

      但我不想。 我希望每个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'
      

      好吧,它似乎要求我提供不同的类型变量而不是类。但为什么?!为什么仅仅在这里Integral就足够了?由于每个quot都声明了Integral,因此该实例对每个Integral都有效,请对其进行调整吗?

      也许有办法达到同样的效果?

1 个答案:

答案 0 :(得分:6)

正如错误消息所示,您可以使用FlexibleInstances(一种相当常见且安全的扩展名)来允许此行为,但您还需要UndecidableInstances

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}

class Proba a where
    proba :: a -> a -> a

instance Integral a => Proba a where
    proba = quot

默认启用此功能的原因是因为它特别是GHC扩展,并且它不是Haskell98规范的一部分。您会发现有很多语言扩展非常有用且使用安全,而且通常只需要在特定模块中启用它们。而不只是问为什么不是这个默认",还要问"我什么时候不希望这是默认的?"。


实现此扩展的另一种方法是将类型类直接编码为数据类型:

data Proba a = Proba
    { proba :: a -> a -> a
    }

integralProba :: Integral a => Proba a
integralProba = Proba quot

然后你可以传递它

foldProba :: Proba a -> a -> [a] -> a
foldProba p = foldr (proba p)

然后,如果您有foldProba integralProba,则会自动将类型约束为Integral a => a -> [a] -> a