实例声明

4

有点好奇为什么在下面需要实例声明,因为已经提供了默认实现。

module Example where

class Eq a => EQ a where
    eq :: a -> a -> Bool
    eq = (==)

-- why is this instance declaration needed?
instance EQ Int where
    eq = (==)

f :: Int -> Int -> Bool
f = eq

如果我省略实例声明,就会出现错误。我确定这在Haskell报告中有解释,但要找到它需要一些时间。

3
因为一个 class 实例不会自动地构造一个 instance - Willem Van Onsem
感谢@WillemVanOnsem。我应该意识到在instance声明中不需要编写where子句。只需编写instance EQ Int即可,它将为Int配备默认的eq实现。 - Marc van Dongen
1个回答

2
我认为您对类的定义,可能更像Java/C#中的“类”。
如果您写下:
class Eq a => EQ a where
    eq :: a -> a -> Bool
    eq = (==)

你只定义了一个类型类:一种为类型类添加函数并编写限制的方式。你没有写明每个 Eq a 都是一个 EQ a... 你写的是为了实现 EQ a,你也必须实现 Eq a(这有点奇怪)。
此外,你提供了一个默认实现:eq = (==),但那只是一个默认实现,当你没有指定实现的情况下。
通过这样写:
instance EQ Int where
    eq = (==)

现在您已经定义了Int是一个EQ。您可以通过编写以下内容使实例更加有用:

instance Eq a => EQ a

现在你已经写出了所有满足Eq a的类型a,并且它们都是EQ类型实例。但是,如果你这么写,那么你立刻就定义了整个EQ宇宙,因为在你的class定义中,你限制了a必须是EQ的实例,这意味着现在,在整个Haskell宇宙中,eq等同于(==)
你可能想表达的是:
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}

class EQ a where
    eq :: a -> a -> Bool

instance Eq a => EQ a where
    eq = (==)

现在你定义了一个类型类 EQ,对于每个类型 a,它都是 Eq a,我们将 eq 设置为 (==),但它也允许你定义其他类型的 EQ,比如不是 Eq 实例的 data Foo。请注意,我们必须在这里启用两个扩展。这些是编译器特定的,因此不是 Haskell 标准的一部分。

谢谢。请确保您的答案反映了这一点并进行解释。如果您这样做,我会接受这个答案。 - Marc van Dongen
@MarcvanDongen:嗯,我们无法知道。每个人都可以自由构建自己的编译器(我的一些朋友就这么做了),他们可以包含/排除任何功能。 :) - Willem Van Onsem
我不同意。你写道“你可能想说”,那么你怎么知道我希望使用ghc(事实上我是这样,但这是无关紧要的)? - Marc van Dongen
@MarcvanDongen:我的意思是它不是GHC特有的。它不是标准的Haskell,但这并不意味着它只适用于单个编译器 :)。这是一个N.B.,我的大部分答案都与问题本身无关,而是寻找改进的方法:)。它通常具有问题陈述-(解决方案)-备注的结构。备注是否有价值当然是不确定的。否则我们就不会称其为研究了。 - Willem Van Onsem
一切都很好,但为什么不通过清楚地指出哪些语句是真实的(Haskell),哪些语句是“非”(方言),从而使答案更容易理解对Haskell知之甚少的新手呢?目前还不清楚... - Marc van Dongen
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接