2013-01-07 7 views
19

タイプの利点同義語ファミリーは明確です - それはタイプレベルの機能です。データファミリの使用例

しかし、データファミリではそうではありません - 私の質問は、データファミリの使用ケースですか?どこで使うべきですか?

+0

既存のタイプを指すのではなく、既存のタイプと同じ意味の新しいシノニムではなく、さまざまなフィールドを持つ既存のタイプまたは通常のレコードをラップする、独自の新タイプを使用することもできます。 'data'で宣言された型を使うのと同じように、これを使うことができます。ただし、今度は型引数に応じて表現が異なることがあります。 –

答えて

23

利点の1つは、データファミリがタイプファミリとは異なり、注入型であることです。

あなたは

type family TF a 
data family DF a 

を持っているなら、あなたはTFと、あなたがいない間、DF a ~ DF bは、そのa ~ bを意味することを知っている - と同じように(任意のaのためにあなたがDF aは全く新しいタイプであることを確認することができます[a]a ~ b以外の場合は[b]とは異なるタイプですが、タイプファミリーは複数の入力タイプを同じ既存タイプにマップできます。

もう1つは、他のタイプのコンストラクタと同様にデータファミリを部分的に適用できることですが、タイプファミリは適用できません。

は、これは特に、現実世界の例ではなく、例えば、あなたが行うことができます:

data instance DF Int = DInt Int 
data instance DF String = DString String 

class C t where 
    foo :: t Int -> t String 

instance C DF where -- notice we are using DF without an argument 
        -- notice also that you can write instances for data families at all, 
        -- unlike type families 
    foo (DInt i) = DString (show i) 

基本的には、DFDF aは他と同じように、自分自身で実際、ファーストクラス、正当な種類の、ありますdataと宣言してください。 TF aは、型に評価される中間形式に過ぎません。

しかし、私はデータファミリーについて疑問を持ち、同様のことを読んでいたときに、それはあまり啓発されていないか、少なくとも私のためではなかったと思います。

私が行った経験則があります。タイプファミリを持つパターンを繰り返すと、入力タイプごとにタイプファミリに新しいタイプのdataが配置されると宣言すると、仲介人を省略して代わりにデータファミリを使用する方が良いでしょう。

vectorライブラリーの実際の例です。 vectorにはいくつかの異なる種類のベクターがあります。ボックス化されたベクター、ボックス化されていないベクター、プリミティブベクター、保存可能なベクターです。各Vectorタイプに対応する変更可能なMVectorタイプ(通常のベクトルは不変です)があります。だから、それは次のようになります。すべてのVectorタイプのために、正確に一つのMutable Vectorタイプがあることを不変エンコード

data family Mutable v :: * -> * -> * 

module Data.Vector{.Mutable} where 
data Vector a = ... 
data instance Mutable Vector s a = ... 
type MVector = Mutable Vector 

module Data.Vector.Storable{.Mutable} where 
data Vector a = ... 
data instance Mutable Vector s a = ... 
type MVector = Mutable Vector 

[etc.] 

を、そこにあること:

type family Mutable v :: * -> * -> * -- the result type has two type parameters 

module Data.Vector{.Mutable} where 
data Vector a = ... 
data MVector s a = ... 
type instance Mutable Vector = MVector 

module Data.Vector.Storable{.Mutable} where 
data Vector a = ... 
data MVector s a = ... 
type instance Mutable Vector = MVector 

[etc.] 

を今すぐその代わりに、私はむしろだろうそれらの間に1対1の対応関係があります。 Vectorの変更可能なバージョンは、常にMutable Vectorと呼ばれます。名前はその名前であり、他にはありません。 Mutable Vectorをお持ちの場合は、対応する不変のタイプVectorを得ることができます。これは、型引数として存在するためです。 type family Mutableを指定すると、それを引数に適用すると、不特定の結果の型(おそらくMVectorと呼ばれますが、わかりません)に評価され、逆方向にマップする方法はありません。