【发布时间】:2012-10-29 20:50:39
【问题描述】:
虽然我知道 GHC 中有一个 TypeSynonymInstances 扩展,但我不知道它有多“危险”,我想知道这个限制是否是任意的,有点像单态限制,或者是否有更深层次的原因它。
【问题讨论】:
虽然我知道 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 检查重叠稍微困难一些。
【讨论】:
据我了解,它有点像单态性限制——摆脱它并没有错,但它会让你面临你可能意想不到的行为。就像单态限制不会伤害任何东西一样——所有类型仍然有效——这也应该是完全安全的:无论如何,类型同义词都有限制,这会阻止它们做任何比简单的名称缩短更花哨的事情(例如,你永远不能部分应用它们,所以我们不会得到类型级别的 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 默认不开启的部分原因。)开启-XOverlappingInstances 比开启-XFlexibleInstances 是a much dodgier idea。
【讨论】:
它曾经是被允许的,但为了让 Haskell 不那么给初学者带来惊喜,它被禁止了。
【讨论】: