5

を使用しようとするとData.Has、次のようなコードを書いています。

data Name = Name; type instance TypeOf Name = Text
type NameRecord = FieldOf Name;

私が見つけた:

instance I NameRecord where
  ...

つまり、コンパイル エラーをスローします。

インスタンスのタイプ シノニム ファミリ アプリケーションが不正です

一方:

instance (NameRecord ~ a) => I a where
  ...

正常にコンパイルされます。

このエラーは、無効とマークされた GHC のこのチケットに関連していると思います。

チケットへの応答は次のように述べています。

あなたが何を提案しているのかわかりません。自動変形はできません

instance C (Fam Int) -- (1)

の中へ

instance (Fam Int ~ famint) => C famint -- (2)

これは、インスタンスが 1 つしかない場合に機能しますが、そのようなインスタンスが 2 つになるとすぐに、それらは常に重複します。

とにかくそれを行うべきであり、プログラマーは暗黙の変換を考慮に入れる必要があると提案しているのかもしれません。これは良い考えだとは思いません。ほとんど利点がなく混乱します (変換されたインスタンスはいつでも簡単に自分で作成できるため)。

おそらく、(1) は失敗するが (2) は失敗しないサンプル コードを使用して、誰かがこの説明について詳しく説明できますか?

4

1 に答える 1

4

(1) は失敗するが (2) は失敗しない場合は些細なことです。型シノニム ( type ExampleOfATypeSynonym = ...) はインスタンス宣言では許可されていませんが、制約では許可されているため、次のようなインスタンスが1 つしかない状況はすべて次のようになります。

-- (1)
class Foo a
type Bla = ()
instance Foo Bla

... 次のように変換できます。

-- (2)
class Foo a
type Bla = ()
instance (a ~ Bla) => Foo a

(1) が失敗する唯一の理由は、型シノニムがインスタンス宣言で許可されていないためです。これは、型シノニムが型関数に似ているためです。型名から型名への一方向のマッピングを提供します。type B = Aおよび の場合、代わりに のインスタンスが作成さinstance Foo Bれることは自明ではありません。Foo Aルールが存在するため、実際にインスタンスを取得するタイプであることをinstance Foo A明確にするために代わりに記述する必要があります。

このコンテキストでは、型ファミリの使用は関係ありません。問題は、型シノニムである型を使用していることにあるからですNameRecord。また、型シノニムが削除されてFieldOf Name直接置き換えられた場合でも、コンパイルは失敗することに注意する必要があります。これは、「型ファミリ」が型シノニムの単なる拡張バージョンであるため、このコンテキストでFieldOf Nameは「型シノニム」でもあるためです。Name :> Text「双方向」の関連付けを取得するには、代わりにデータ ファミリとデータ インスタンスを使用する必要があります。

データ ファミリの詳細については、GHC のドキュメントを参照してください。


「... (2) は失敗するが (1) は失敗する...」という意味だと思います

次のような型クラスがあるとします。

class Foo a where
  foo :: a

これで、次のようにインスタンスを記述できます。

 instance Foo Int where
   foo = 0

 instance Foo Float where
   foo = 0

 main :: IO ()
 main = print (foo :: Float)

これは期待どおりに機能します。ただし、コードを次のように変換すると:

{-# LANGUAGE FlexibleInstances, TypeFamilies #-}
class Foo a where
  foo :: a

instance (a ~ Int) => Foo a where
  foo = 0

instance (a ~ Float) => Foo a where
  foo = 0

main :: IO ()
main = print (foo :: Float)

コンパイルされません。次のエラーが表示されます。

test.hs:5:10:
    Duplicate instance declarations:
      instance a ~ Int => Foo a -- Defined at test.hs:5:10-27
      instance a ~ Float => Foo a -- Defined at test.hs:8:10-29

したがって、これはあなたが探していた例です。Foo現在、これは、このトリックを使用するのインスタンスが複数ある場合にのみ発生します。何故ですか?

GHC が型クラスを解決するとき、インスタンス宣言の先頭だけを調べます。つまり、 の前のすべてを無視します=>。インスタンスを選択すると、それに「コミット」し、その前に制約をチェックして、=>それらが真であるかどうかを確認します。したがって、最初に 2 つのインスタンスが表示されます。

instance Foo a where ...
instance Foo a where ...

この情報だけに基づいて、どのインスタンスを使用するかを決定することは明らかに不可能です。

于 2012-05-07T11:52:29.103 に答える