でdata
宣言、型コンストラクタは、等号の左側のものです。データコンストラクタ(S)等号の右側のものです。型が期待される場所では型コンストラクタを使用し、値が期待される場所ではデータコンストラクタを使用します。
データコンストラクター
簡単にするために、色を表すタイプの例から始めることができます。
data Colour = Red | Green | Blue
ここには、3つのデータコンストラクタがあります。Colour
は型であり、型のGreen
値を含むコンストラクタですColour
。同様に、Red
およびBlue
は、両方ともtypeの値を構築するコンストラクタですColour
。私たちはそれをスパイスアップすることを想像することができました!
data Colour = RGB Int Int Int
型だけが残ってColour
いますRGB
が、値ではありません。3つのIntを取り、値を返す関数です。RGB
タイプがあります
RGB :: Int -> Int -> Int -> Colour
RGB
いくつかの値を引数として取り、それらを使用して新しい値を構築する関数であるデータコンストラクターです。オブジェクト指向プログラミングを実行したことがある場合は、これを認識してください。OOPでは、コンストラクターもいくつかの値を引数として取り、新しい値を返します!
この場合、RGB
3つの値に適用すると、色の値が取得されます。
Prelude> RGB 12 92 27
#0c5c1b
私たちはしている値を構築タイプのをColour
データコンストラクタを適用することで。データコンストラクターは、変数のように値を含むか、他の値を引数として取り、新しい値を作成します。以前のプログラミングを実行したことがある場合、この概念はそれほど奇妙なものではないはずです。
休憩
を格納するバイナリツリーを作成するString
場合は、次のようなことを想像できます。
data SBTree = Leaf String
| Branch String SBTree SBTree
ここに表示されているのは、SBTree
2つのデータコンストラクターを含む型です。つまり、型の値を構成する2つの関数(つまりLeaf
およびBranch
)がありますSBTree
。バイナリツリーの動作に慣れていない場合は、そこにいるだけで十分です。バイナリツリーがどのように動作するかを実際に知る必要はありませんString
。このツリーが何らかの方法でsを保存しているということだけです。
また、両方のデータコンストラクターがString
引数を取ることもわかります。これは、ツリーに格納する文字列です。
だが!も格納できるようにしたい場合はBool
、新しいバイナリツリーを作成する必要があります。次のようになります。
data BBTree = Leaf Bool
| Branch Bool BBTree BBTree
型コンストラクタ
SBTree
とBBTree
は両方とも型コンストラクタです。しかし、明白な問題があります。それらがどれほど似ているかわかりますか?これは、どこかに本当にパラメータが必要であることを示しています。
これを行うことができます:
data BTree a = Leaf a
| Branch a (BTree a) (BTree a)
次に、型コンストラクターのパラメーターとして型変数 を導入しa
ます。この宣言でBTree
は、関数になっています。引数として型を取り、新しい型を返します。
それは違いを検討するためにここで重要なのは、具体的なタイプ(例としてはInt
、[Char]
そしてMaybe Bool
あなたのプログラム内の値に割り当てることができるタイプである)を、そして型コンストラクタ関数あなたはタイプを供給する必要があることができるようにするには値に割り当てられます。「何かのリスト」である必要があるため、値のタイプを「リスト」にすることはできません。同じ趣旨で、値は「何かを格納するバイナリツリー」である必要があるため、「バイナリツリー」タイプにすることはできません。
たとえばBool
、引数としてを渡すと、s を格納するバイナリツリーであるBTree
タイプを返します。型変数のすべての発生を置き換えタイプで、そしてあなたはそれが本当だか自分で見ることができます。BTree Bool
Bool
a
Bool
必要に応じて、種類をBTree
関数として表示できます
BTree :: * -> *
種類はややタイプに似ています–は*
具体的なタイプを示すのでBTree
、具体的なタイプから具体的なタイプへと言います。
まとめ
ここで少し戻って、類似点に注意してください。
値にわずかなバリエーションが必要な場合、パラメーター付きのデータコンストラクターはすばらしいです。これらのパラメーターのバリエーションをパラメーターに入れ、値を作成する人にどの引数を入れるかを決定させます。同じ意味で、パラメーターを持つタイプコンストラクターはすばらしいですタイプにわずかなバリエーションが必要な場合!これらのバリエーションをパラメーターとして配置し、型を作成する人に、どの引数を入力するかを決定させます。
ケーススタディ
ここのホームストレッチとして、Maybe a
タイプを考えることができます。その定義は
data Maybe a = Nothing
| Just a
以下Maybe
は具象型を返す型コンストラクタです。Just
値を返すデータコンストラクターです。Nothing
値を含むデータコンストラクターです。のタイプJust
を見ると、
Just :: a -> Maybe a
つまり、Just
typeの値を取り、type a
の値を返しますMaybe a
。の種類Maybe
を見ると、
Maybe :: * -> *
つまり、Maybe
具象型を取り、具象型を返します。
もう一度!具体的な型と型コンストラクタ関数の違い。Maybe
sのリストを作成することはできません-実行しようとした場合
[] :: [Maybe]
エラーが発生します。ただしMaybe Int
、またはのリストを作成できますMaybe a
。これMaybe
はが型コンストラクタ関数であるためですが、リストには具象型の値を含める必要があります。Maybe Int
およびMaybe a
具象型です(または、必要に応じて、具象型を返す型コンストラクタ関数の呼び出し)。
Car
、型コンストラクター(の左側=
)とデータコンストラクター(右側)の両方であるため、少しわかりにくいかもしれません。最初の例では、Car
型コンストラクターは引数を取らず、2番目の例では3つ引数を取ります。どちらの例でも、Car
データコンストラクターは3つの引数を取ります(ただし、これらの引数の型は1つの場合は固定され、他の場合はパラメーター化されます)。