为什么Haskell在声明类实例时不允许使用Type Synonyms?

时间:2012-10-29 05:18:07

标签: haskell typeclass

虽然我知道GHC中存在TypeSynonymInstances扩展,但我不知道它是多么“危险”,我想知道这种限制是否是任意的,有点像单态限制,或者是否有更深层次的限制原因。

3 个答案:

答案 0 :(得分:24)

TypeSynonymInstances非常安全。由于不允许任何可能像部分应用类型同义词一样的幻想,它与在实例头中键入同义词类型右侧的效果完全相同,即

type Foo a = ([a], [a])
instance Bar (Foo a)

相同
instance Bar ([a], [a])

但请注意,两个实例都需要FlexibleInstances,因为它们包含嵌套类型构造函数以及重复的类型变量。通常,在扩展类型同义词之后通常会出现这种情况。

我认为可能是他们默认不被禁止的原因。

但是,FlexibleInstances也是一个非常安全的扩展。如果您尝试定义重叠实例(例如

),它可以做的最糟糕的事情是导致编译时错误
instance Xyzzy String
instance Xyzzy [a]

至于为什么FlexibleInstances默认不可用,我只能猜测它是为了简化语言。实例定义的标准规则确保实例定义可以重叠的唯一方法是实例头中的类型构造函数是否相同,而使用FlexibleInstances检查重叠则稍微困难。

答案 1 :(得分:15)

据我了解,它有点像单态限制 - 没有什么错误关于摆脱它,但它打开了你可能没想到的行为。就像单形态限制不会伤害任何东西 - 所有类型仍然有效 - 这也应该是完全安全的:无论如何都有类型同义词的限制,这阻止他们做任何比简单名称缩短更精彩的事情(例如< / em>,你永远不能部分应用它们,所以我们不会得到类型级lambdas),因此你总是可以用它们定义的右侧替换它们。因此,由于这些定义的右侧可以作为实例头检查(或包含进一步扩展的类型同义词),因此不应该发生任何不安全的事情。

另一方面,正如禁用单态限制一样,您可能会遇到奇怪的性能特征,启用类型同义词实例可能会导致潜在的奇怪类型类错误。因此,让我们启用-XTypeSynonymInstances并尝试使用类型同义词编写实例:

Prelude> :set -XTypeSynonymInstances
Prelude> instance Num String where (+) = (++)

<interactive>:3:10:
    Illegal instance declaration for `Num String'
      (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 -XFlexibleInstances if you want to disable this.)
    In the instance declaration for `Num String'

String看起来像一个普通的旧类型,所以这一开始可能会令人惊讶;但它确实是[Char],因此根据Haskell 2010的严格规则,此实例无效。如果我们通过启用-XFlexibleInstances(顺便提一下,implies -XTypeSynonymInstances)来放宽这些规则,此示例现在可以使用:

Prelude> :set -XFlexibleInstances
Prelude> instance Num String where (+) = (++)
... errors about undefined methods ...
Prelude> "a" + "b"
"ab"

但事情变得很丑陋:

Prelude> instance Eq String where
Prelude> "a" == "b"

<interactive>:8:5:
    Overlapping instances for Eq [Char]
      arising from a use of `=='
    Matching instances:
      instance Eq a => Eq [a] -- Defined in `GHC.Classes'
      instance Eq String -- Defined at <interactive>:7:10
    In the expression: "a" == "b"
    In an equation for `it': it = "a" == "b"

同样,即使String看起来像一个不同的类型,我们已经有[a]的实例,所以这与它重叠。 (事实上​​,这可能是默认情况下-XFlexibleInstances未启用的部分原因。)启用-XOverlappingInstancesa much dodgier idea而不是启用-XFlexibleInstances

答案 2 :(得分:6)

曾经允许这样做,但是为了让Haskell对初学者不那么充满惊喜,它被禁止了。