Haskell实例声明影响类的解释

时间:2015-03-01 06:20:04

标签: haskell

除非删除实例声明,否则下面的代码会给出此错误。另外,我不知道谷歌会发生什么,因为错误与导致问题的原因无关?

Test.hs|20 col 31 error| Could not deduce (Integral a) arising from a use of `gendivmod'
|| from the context (Euclidean a)
||   bound by the type signature for
||              gcdBezouts :: Euclidean a => a -> a -> (a, a, a)
||   at /home/jragonfyre/src/haskell/mathlib/Test.hs:17:15-50
|| Possible fix:
||   add (Integral a) to the context of
||     the type signature for
||       gcdBezouts :: Euclidean a => a -> a -> (a, a, a)
|| In the expression: gendivmod x y
|| In a pattern binding: (q, r) = gendivmod x y
|| In the expression:
||   let
||     (q, r) = gendivmod x y
||     (n, m, d) = gcdBezouts y r
||   in (m, n - m * q, d)

这是一个在我的机器上重现错误的MWE。

{-# LANGUAGE FlexibleInstances, UndecidableInstances #-}

class (Num a, Eq a) => Euclidean a where
  genmod :: a -> a -> a
  genmod a = snd . gendivmod a
  gendiv :: a -> a -> a
  gendiv a = fst . gendivmod a
  gendivmod :: a -> a -> (a,a)
  gendivmod a b = (gendiv a b, genmod a b)
  isUnitEu :: a -> Bool
  isUnitEu = (==1) . abs

instance (Integral a) => Euclidean a where
  gendivmod = divMod

gcdBezouts :: (Euclidean a) => a -> a -> (a, a, a)
gcdBezouts 0 x = (0, 1, x)
gcdBezouts x 0 = (1, 0, x)
gcdBezouts x y = let (q, r) = gendivmod x y
                     (n, m, d) = gcdBezouts y r
                 in (m, n-m*q, d)

至于不使用newtype的动机,以及特定的实例声明,我有很多为整数编写的现有代码,我想要推广使用多项式,而且我没有&#39 ; t想要将包装和展开新类型重写为一个丑陋的混乱。

如果有另一种解决方案可以实现我的目标,那也值得赞赏。

1 个答案:

答案 0 :(得分:4)

我不确定你为什么认为你需要一个新类型。

“超类实例”

instance (Integral a) => Euclidean a where

您可能认为“Integral的每个实例也是Euclidean的实例”实际上意味着“每个类型都是Euclidean的实例,稍后添加约束,在实例化时我们需要Integral“。这种情况总是会给你带来麻烦。

我建议明确地在您需要的每种类型中实例化Euclidean(这也允许您摆脱UndecidableInstances)。

instance Euclidean Integer where
    ...

如果您在许多Integral类型中实例化它,您应该编写帮助程序:

integralGenmod :: (Integral a) => a -> a -> a
...

或者,既然你的班级有很多方法,那就从启示:

开始
data EuclideanDomain a = EuclideanDomain a {
    edGenmod :: a -> a -> a,
    ...
}
class Euclidean a where
    euclideanDomain :: EuclideanDomain a

genmod :: (Euclidean a) => a -> a -> a
genmod = edGenmod euclideanDomain    
...

integralEuclidean :: (Integral a) => EuclideanDomain a
integralEuclidean = EuclideanDomain { ... }

instance Euclidean Integral where
    euclideanDomain = integralEuclidean

这使得显式实例化更易于管理,并且还允许您声明结构的更多组成属性。 (参见此post,通过对类型类进行实现可以帮助您获得很长的路径)