型クラスと型ファミリーを混合する場合の問題
-
25-09-2019 - |
質問
このコードは正常にコンパイルされます。
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables,
TypeOperators, TypeSynonymInstances, TypeFamilies #-}
class Sel a s b where
type Res a s b :: *
instance Sel a s b where
type Res a s b = (s -> (b,s))
instance Sel a s (b->(c,a)) where
type Res a s (b->(c,a)) = (b -> s -> (c,s))
しかし、R 述語を追加するとすぐに ghc が失敗します。
{-# LANGUAGE MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances,
UndecidableInstances, FlexibleContexts, EmptyDataDecls, ScopedTypeVariables,
TypeOperators, TypeSynonymInstances, TypeFamilies #-}
class Sel a s b where
type Res a s b :: *
instance Sel a s b where
type Res a s b = (s -> (b,s))
class R a where
type Rec a :: *
cons :: a -> Rec a
elim :: Rec a -> a
instance Sel a s (b->(c,Rec a)) where
type Res a s (b->(c,Rec a)) = (b -> s -> (c,s))
次のように不平を言っています。
Illegal type synonym family application in instance:
b -> (c, Rec a)
In the instance declaration for `Sel a s (b -> (c, Rec a))'
それは何を意味するのでしょうか?そして (最も重要なことですが) それを修正するにはどうすればよいですか?
ありがとう
解決
タイプファミリーは一方通行です:あなたは、その計算された型にRec a
を展開することができますが、(一意)Rec a
に拡張バックから行くことができません。彼らは適用するインスタンスをトリガーすることはできませんので、これは、インスタンスの署名のための型の関数のアプリケーションは不向きます。
あなたが代わりに試みることができる:
instance Rec a ~ reca => Sel a s (b->(c,reca))
この手段は何か他のもの:それは取消不能一致したときに任意の関数のb -> (c, reca)
がインスタンスであると言い、そして、コンパイラチェックRec a ~ reca
います。しかし、これはあなたのケースで必要を行うには良い十分かもしれません。
他のヒント
Rec
型コンストラクターではありません。それは型関数です。おそらく、クラス宣言ではなく、型定義の値の型でのみ使用できますか?ここで私はかなり推測しています。型ファミリーのルールをすべて理解していません。
修正方法はわかりませんが、次のことを試してみてください。
Sel クラスを削除して定義だけを行う
type family Res a s b :: *
. 。使用type instance
クラスメカニズムの代わりに。タイプを作る可能性はほとんどありません
Rec
単射を使ってdata
役に立つだろうが、私はそうは思わない。機能する可能性のある言語拡張機能の数を最小限に抑えます。そうすることで、他の人があなたを助けてくれやすくなり、コンパイラにとっても役立つ可能性があります。
それはあなたがタイプのインスタンスを宣言する際に型synomymファミリを使用することを許可されていないことを意味します。セクションを参照してください。 「タイプ家族とインスタンス宣言」マニュアルGHCののます。
あなたはそれを修正することができる唯一の方法は、何とかそれを必要としないようにリファクタリングすることです。