为什么Haskell在声明类实例时不允许类型同义词



虽然我知道GHC中有一个typesynonyminstances扩展,但我不知道它是多么"危险",我想知道这种限制是否是任意的,有点像单态限制,或如果有更深的原因。

TypeSynonymInstances是完全安全的。由于不允许使用任何潜在的幻想,例如部分应用类型的同义词,因此其效果与键入实例头部类型同义词的右手侧的效果完全相同,即。

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

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

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

我认为可能是默认禁止它们的原因。

但是,FlexibleInstances也是一个完全安全的扩展。最糟糕的是,如果您尝试定义重叠实例,例如

instance Xyzzy String
instance Xyzzy [a]

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

,据我了解,它有点像单态限制 - 摆脱它没有什么错误预计。就像单态限制不会伤害任何东西一样 - 所有类型仍然有效 - 这也应该是完全安全的:无论如何,对类型的同义词都有限制,这阻止了他们做任何比简单的名称缩短的事情(例如 e,例如/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(顺便说明-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不在默认情况下不打开的部分原因。)并且打开-XOverlappingInstances比打开-XFlexibleInstances是一个多功能的想法。

它曾经允许,但是在试图使哈斯克尔(Haskell)不那么惊喜的初学者中,它被禁止了。

最新更新