2012-08-03 26 views
6

私はソースコードData.Hasを探していて、どのように動作するかを調べようとしていました。次のコードは、誰かがa :: Ab :: Bという2つの値を「a」と「b」の両方の機能を持つ新しい値に「結合」できるようにするためのコードだと考えています。クラス宣言とインスタンス宣言の型キーワード

私は特に、typeがクラス宣言とインスタンス宣言の中にあることを理解していません。

また、~シンボルの意味は分かりません。

誰かが下記のコードをData.Has.TypeListから説明できますか?型クラスおよびインスタンス宣言内部

-- | Provides type-list functionality 

module Data.Has.TypeList where 

import Control.Applicative 
import Data.Monoid (Monoid (..)) 
import Test.QuickCheck (Arbitrary (..), CoArbitrary (..)) 
import Data.Typeable 
import Data.Data 
-- | Cons a type onto type-list. 
data a ::: b = a ::: b deriving (Show,Eq,Ord,Read,Bounded,Typeable,Data) 

-- | The empty type-list. 
data TyNil = TyNil deriving (Read,Typeable,Data) 

-- | Appends a type-list and another. 
class Append a b where 
    type a :++: b 
    (.++.) :: a -> b -> a :++: b 
infixr 5 :++: 

-- Implementation of Append 

instance Append TyNil b where 
    type TyNil :++: b = b 
    _ .++. b = b 

instance (Append y b) => Append (x ::: y) b where 
    type (x ::: y) :++: b = x ::: (y :++: b) 
    ~(x ::: y) .++. b = x ::: (y .++. b) 
+0

これらは、関連タイプの同義語と呼ばれます。これらの構文は関数の依存関係に似ていますが、関係の代わりに型関数を使用します。 –

答えて

7

type構文は、TypeFamilies拡張の一部です。型族は型から型への関数と考えることができます。 Haskell wikiの型とデータファミリの詳細な説明があります(リンクを参照)。

タイプクラスに適用されるタイプファミリは、の関連タイプになります。この点で、彼らはFunctionalDependenciesに非常に近く、つまり、明確なインスタンス解決が可能です。これの必要性については、十分に説明されているin the GHC manualです。

あなたの例の型定義は非常に簡単です。 :::は2タプル(値のペア)の別の名前であり、TyNilはユニットタイプ()と同形です。

クラスとインスタンスの宣言を読んで、その意味を明確にします。

class Append a b where 
    type a :++: b 
    (.++.) :: a -> b -> a :++: b 
infixr 5 :++: 

関連タイプa :++: b及びタイプabの値を取り、型a :++: bの値を与える一つの方法機能(.++.)Append a b型クラス宣言マルチパラメータ。我々はまた、固定された第一のパラメータ(TyNil)及び任意の第二パラメータ(b)、関連するタイプa :++: b(中でAppend a bのインスタンスを宣言右結合優先5

instance Append TyNil b where 
    type TyNil :++: b = b 
    _ .++. b = b 

となるように(.++.)を設定しましたこの場合はTyNil :++: b)はbと等しいと宣言されます。 (私はどのような方法を説明しません、それはかなり明確です)。

instance (Append y b) => Append (x ::: y) b where 
    type (x ::: y) :++: b = x ::: (y :++: b) 
    ~(x ::: y) .++. b = x ::: (y .++. b) 

宣言Append y bのインスタンスが既に存在することを与えられた任意xyのフォームx ::: yの最初のパラメータと任意の第二パラメータbAppend a bのインスタンスを宣言。関連タイプa :++: b(ここでは(x ::: y) :++: b、明らかに)はx ::: (y :++: b)と等しいと宣言されています。メソッドの定義もここではっきりしています。つまり、値のペアと別の値をとり、最初の要素が最初の引数と同じで、2番目の要素が最初の引数の2番目の要素で、2番目の引数と.++.メソッドの2番目の要素です。我々は、.++.ためAppend y b制約

の使用を許可され、これらは、クラス宣言とインスタンス宣言で(.++.)メソッドの型シグネチャである:

(.++.) ::    a  -> b -> a :++: b 
(.++.) ::    TyNil -> b -> b 
(.++.) :: Append y b => x ::: y -> b -> x ::: (y :++: b) 

a :++: b非常に抽象各インスタンスでのより具体的なタイプを変換すること。最初のケースでは普通のbで、:++:という言葉で書かれたより複雑なx ::: (y :++: b)です。関連するタイプの

このような宣言は、一意a単独bによって決定されるいくつかのタイプ(この場合a :++: b)があること型システムを伝えるために必要とされます。型チェッカーは、特定の表現にab種類がIntDouble、たとえば、同じであることを知っている、とあれば、次のとおりです。

  1. が制約Append a bあります。
  2. 型クラスのインスタンスAppend Int Double

は、型チェッカーは、彼がタイプa :++: bを満たしていれば、それは実際にはこのタイプがStringであることを知っているだろうことを知っているだろう、type Int :++: Double = Stringとして、たとえば、宣言に関連するタイプとがあります。

~は「レイジーパターンマッチ」と呼ばれます。それは非常に明確にhereと説明されています。

まだ不明な点がありましたらお気軽にお問い合わせください。