次のコードがあるとしましょう。
class C t where
g :: t
instance C Int where
g = 42
単純。次のように、Int で関数を定義することもできます。
f1 :: Int -> Int
f1 x = x * x
私は型ファミリを使用してきましたが、特に型ファミリをData.Has
使用しているため、IxSet
.
しかし、ここでは簡単な例を示します。X
Int に似た新しい type を定義したいとしましょう。これを行うことができます:
type family X
type instance X = Int
X
次に、次のように関数を定義できます。
f2 :: X -> X
f2 x = x * x + 1
これまでのところ問題はありません。C X
で行ったように、インスタンスを定義してみましょうC Int
。
instance C X where
g = 43
おっと、次のエラーが発生しました。
インスタンスの型シノニム ファミリ アプリケーションが正しくありません:
X
のインスタンス宣言で'C X'
次に、少し違うことを試してみましょう。
newtype NewX = NewX X
instance C NewX where
g = 43
ここで、別のエラーが発生しました。つまり、次のとおりです。
(Num NewX)
リテラルから生じるインスタンスはありません'43'
newtype
キーワードにより、前のクラスがどのクラスに属していたかに関する情報も削除されるようです。ただし、newtype
インスタンス定義で型ファミリを使用できないため、回避できないようです。
そうでなければ推論される追加の明示的なインスタンスの言及でインスタンス定義を書き直す必要なしにこれを行うより良い方法はありますか?
背景情報:
これが機能する必要がある理由は次のとおりです。
import Data.Has
import Data.IxSet
data Col1 = Col1; type instance TypeOf Col1 = Text
data Col2 = Col2; type instance TypeOf Col2 = Text
type Row = FieldOf Col1 :&: FieldOf Col2;
instance Indexable Row where
empty = ixSet [ixFun $ (\x -> [ Col1 ^. x ]) ] -- Maybe add some more indexes later
これは次の場合に失敗します。
インスタンスの型シノニム ファミリ アプリケーションが正しくありません:
Row
のインスタンス宣言で'Indexable Row'
を作成Row
するnewtype
と、次のエラーが発生します。
`^' の使用に起因する (Contains (Labelled Col1 Text) Row) のインスタンスはありません。考えられる修正: (Contains (Labelled Col1 Text) Row) のインスタンス宣言を追加します。
これを回避できる唯一の方法は、次のように長い派生句を追加することです。
newtype Row = Row (FieldOf Col1 :&: FieldOf Col2)
deriving
(
Contains (Labelled Col1 Text), -- Add this for every column
Contains (Labelled Col2 Text) -- ...
)
「typedef」Contains (Labelled x (TypeOf x))
して言うHasCol x
ことを可能にするものでさえ役に立ちます。