GHCにTypeSynonymInstances拡張機能があることは知っていますが、それがどれほど「危険」であるかはわかりません。この制限が任意であるか、単相制限のようなものか、それとももっと深い理由があるのでしょうか。
3 に答える
TypeSynonymInstances
完全に安全です。部分的に適用されたタイプシノニムのような潜在的に派手なものは許可されないため、インスタンスヘッドにタイプシノニムの右側を入力するのとまったく同じ効果があります。
type Foo a = ([a], [a])
instance Bar (Foo a)
と同じです
instance Bar ([a], [a])
ただし、両方のインスタンスFlexibleInstances
にはネストされた型コンストラクターと繰り返し型変数が含まれているため、両方のインスタンスが必要であることに注意してください。一般に、これはタイプの同義語を拡張した後によく発生します。
デフォルトで許可されていない理由かもしれません。
ただし、FlexibleInstances
これは完全に安全な拡張機能でもあります。最悪の場合、次のような重複するインスタンスを定義しようとすると、コンパイル時エラーが発生します。
instance Xyzzy String
instance Xyzzy [a]
なぜFlexibleInstances
デフォルトで利用できないのかというと、それは言語を単純化するためだと私は推測することができます。インスタンスヘッドの標準ルールでは、インスタンス定義がオーバーラップできる唯一の方法は、インスタンスヘッドの型コンストラクターが同一である場合ですが、FlexibleInstances
オーバーラップのチェックは少し難しくなります。
私が理解しているように、それは単相性の制限のようなものです。それを取り除くことには何の問題もありませんが、それはあなたが予期しない行動にあなたを開放します。単相性の制限が何も害を及ぼさないのと同じように(すべての型はまだ有効です)、これも完全に安全である必要があります。とにかく型の同義語に制限があり、単純な名前の短縮よりも面白いことを行うことができません(たとえば、決してそれらを部分的に適用するため、タイプレベルのラムダは取得されません)。したがって、いつでもそれらを定義の右側に置き換えることができます。したがって、これらの定義の右側はインスタンスヘッドとしてチェックできるため(または拡張するためにさらに型の同義語を含めることができるため)、安全でないことは何も起こらないはずです。
一方、単相制限を無効にすると、潜在的に奇妙なパフォーマンス特性が発生するのと同様に、型同義語インスタンスを有効にすると、潜在的に奇妙な型クラスエラーが発生する可能性があります。それでは、有効-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を初心者の驚きに満ちないようにするために、禁止されました。