简体   繁体   English

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

[英]Why does Haskell not allow Type Synonyms when declaring class instances?

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

TypeSynonymInstances is perfectly safe. TypeSynonymInstances非常安全。 Since anything potentially fancy like partially applied type synonyms is disallowed, it has exactly the same effect as typing out the the right hand side of the type synonym in the instance head, ie 由于不允许任何可能像部分应用类型同义词一样的奇特,它与在实例头中键入类型同义词的右侧具有完全相同的效果,即

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

is the same as 是相同的

instance Bar ([a], [a])

However, note that both instances require FlexibleInstances since they contain nested type constructors as well as repeated type variables. 但请注意,两个实例都需要FlexibleInstances因为它们包含嵌套类型构造函数以及重复类型变量。 In general, this will often be the case after expanding type synonyms. 通常,在扩展类型同义词之后通常会出现这种情况。

I think may be the reason why they're disallowed by default. 我想可能是他们默认不被禁止的原因。

However, FlexibleInstances is also a perfectly safe extension. 但是, FlexibleInstances也是一个非常安全的扩展。 The worst it can do is cause a compile-time error if you try to define overlapping instances such as 如果你试图定义重叠的实例,它可以做的最糟糕的是导致编译时错误

instance Xyzzy String
instance Xyzzy [a]

As for why FlexibleInstances is not available by default, I can only guess that it's to simplify the language. 至于为什么FlexibleInstances默认不可用,我只能猜测它是为了简化语言。 The standard rules for instance heads ensures that the only way instance definitions can overlap is if the type constructors in the instance heads are identical, while with FlexibleInstances checking for overlaps is slightly more difficult. 实例定义的标准规则确保实例定义可以重叠的唯一方式是实例头中的类型构造函数是否相同,而使用FlexibleInstances检查重叠则稍微困难一些。

As I understand it, it's sort of like the monomorphism restriction—there's nothing wrong about getting rid of it, but it opens you up to behavior you might not expect. 据我了解,它有点像单态限制 - 摆脱它没有什么不对 ,但它打开了你可能没想到的行为。 Just like the monomorphism restriction doesn't hurt anything—all the types are still valid—this also ought to be totally safe: there are restrictions on type synonyms anyway which prevent them from doing anything fancier than simple name shortening ( eg , you can never partially apply them, so we don't get type-level lambdas), and so you can always replace them with the right-hand side of their definition. 就像单同性限制不会伤害任何东西 - 所有类型仍然有效 - 这也应该是完全安全的:无论如何,类型同义词都有限制,阻止他们做比简单名称缩短更好的事情( 例如 ,你永远不能部分应用它们,所以我们没有获得类型级lambdas),所以你总是可以用它们定义的右侧替换它们。 Thus, since the right-hand sides of those definitions can be checked as instance heads (or contain further type synonyms to expand out), nothing unsafe should be going on. 因此,由于这些定义的右侧可以作为实例头检查(或包含进一步扩展的类型同义词),因此不应该发生任何不安全的事情。

On the other hand, just as disabling the monomorphism restriction opens you up to potentially odd performance characteristics, enabling type synonym instances opens you up to potentially odd type class errors. 另一方面,正如禁用单态限制一样,您可能会遇到奇怪的性能特征,启用类型同义词实例可能会导致潜在的奇怪类型类错误。 So let's enable -XTypeSynonymInstances and try writing an instance with a type synonym: 因此,让我们启用-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 looks like a plain old type, so this might be surprising at first; String看起来像一个普通的旧类型,所以这一开始可能会令人惊讶; but it's really [Char] , and so this instance is invalid according to Haskell 2010's strict rules. 但它真的是[Char] ,所以根据Haskell 2010严格的规则,这个实例是无效的。 If we relax those rules by turning turn on -XFlexibleInstances (which, incidentally, implies -XTypeSynonymInstances ), this example works now: 如果我们通过启用-XFlexibleInstances (顺便-XTypeSynonymInstances暗示-XTypeSynonymInstances )来放宽这些规则,这个示例现在可以正常工作:

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

But things gets ugly fast: 但事情变得很难看:

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"

Again, even though String looks like a distinct type, we already have an instance for [a] , and so this overlaps with it. 同样,即使String看起来像一个不同的类型,我们已经有[a]的实例,所以这与它重叠。 (And in fact, this is probably part of why -XFlexibleInstances isn't on by default.) And turning on -XOverlappingInstances is a much dodgier idea than turning on -XFlexibleInstances . (事实上,这可能是为什么部分-XFlexibleInstances是不是在默认情况下)并打开-XOverlappingInstances一个更dodgier想法比打开-XFlexibleInstances

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM