如何在没有派生的情况下实例化

时间:2017-05-15 08:57:12

标签: haskell instance typeclass

抱歉我的英语不好。标题可能无法解释我的意思。

在Data.Tree中,Tree定义如下:

-- | Multi-way trees, also known as /rose trees/.
data Tree a = Node {
        rootLabel :: a,         -- ^ label value
        subForest :: Forest a   -- ^ zero or more child trees
    }
#ifdef __GLASGOW_HASKELL__
  deriving (Eq, Read, Show, Data)
#else
  deriving (Eq, Read, Show)
#endif

它使用deriving实例==/= Tree(日期)。

我可以在没有衍生的情况下做同样的事情吗? 我尝试这样的事情:

data Test a = Test a
instance Eq Test where
    (Test a) == (Test b) = a == b

但它引发了一个例外。我认为原因在于a和b的类型。

如果我想使用==为我的数据定义自定义操作,我该怎么办。

我知道我可以Functor使用fmap来执行此操作。但我希望==使用a == b a = Test 1b = Test "a"。有可能吗?

1 个答案:

答案 0 :(得分:9)

可以在instanceEq上定义Tree Test ,但有一些问题用你的定义。

instance Eq Test where
    (Test a) == (Test b) = a == b

第一个问题是Test中的Eq Test 仍然是参数化的。实际上,您编写了data Test a = ...,这意味着存在类型参数。所以你可以用:

指定它
instance Eq (Test a) where
    (Test y) == (Test x) = x == y

现在您指定Eq定义为Test a。我还将ab重命名为xy。这不是必要的,因为“类型世界”和“变量世界”是分开的,但它使事情变得不那么混乱。

但仍有问题:你致电x == y。但没有保证a本身就是Eq 的实例。因此,您需要使用类型约束

instance Eq a => Eq (Test a) where
    (Test y) == (Test x) = x == y

现在您指定Test aEq 的实例,如果 a也是Eq的实例。

对于您的Tree数据结构,instance的{​​{1}}应该如下所示:

Eq

(当然我在这里定义两个树是如何相同的,你可能希望以(语义)不同的方式定义两棵树的相等性,所以你不应该本身复制粘贴此代码。)

请注意 - 与@luqui一样 - 如果instance (Eq a, Eq (Forest a)) => Eq (Tree a) where (Tree x1 y1) == (Tree x2 y2) = x1 == x2 && y1 == y2 ,那么您可以省略 type Forest a = [Tree a]类型约束,因为Eq (Forest a)成立。所以在这种情况下它是:

instance Eq a => Eq [a]