私はHaskellを学んでいます詳しくはこちら型コンストラクタとデータコンストラクタを理解するのに苦労しています。たとえば、次の違いがよくわかりません。
data Car = Car { company :: String
, model :: String
, year :: Int
} deriving (Show)
この:
data Car a b c = Car { company :: a
, model :: b
, year :: c
} deriving (Show)
最初の方法は、単に 1 つのコンストラクター ( Car
) を使用して、 型のデータを構築するだけであることは理解していますCar
。2 番目についてはよくわかりません。
また、データ型は次のように定義されます。
data Color = Blue | Green | Red
これらすべてに当てはまるでしょうか?
私の理解では、3 番目の例 ( Color
) は、Blue
、Green
または の3 つの状態をとることができる型Red
です。しかし、これは最初の 2 つの例の理解と矛盾しています。つまり、型はCar
1 つの状態、つまり のみをとることができCar
、その状態はさまざまなパラメータを使用して構築できるということでしょうか。そうであれば、2 番目の例はどのように当てはまるでしょうか。
本質的には、上記の 3 つのコード例/構造を統合する説明を探しています。
ベストアンサー1
宣言ではdata
、型コンストラクタ等号の左側にあるものです。データコンストラクタ等号の右側にあるものです。型が期待される場所では型コンストラクタを使用し、値が期待される場所ではデータコンストラクタを使用します。
データコンストラクタ
簡単にするために、色を表す型の例から始めましょう。
data Colour = Red | Green | Blue
ここでは、3 つのデータ コンストラクターがあります。Colour
は型で、 はGreen
型 の値を含むコンストラクターですColour
。同様に、Red
と はBlue
どちらも型 の値を構築するコンストラクターです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
。データコンストラクタは、変数のように値を格納するか、他の値を引数として受け取り、新しい型を作成します。価値これまでにプログラミングを経験したことがある人にとって、この概念はそれほど奇妙ではないはずです。
休憩
sを格納するためのバイナリツリーを構築したい場合はString
、次のようなことを想像できます。
data SBTree = Leaf String
| Branch String SBTree SBTree
ここで見られるのは、2 つのデータ コンストラクターを含む型ですSBTree
。言い換えると、型の値を構築する2 つの関数 (つまりLeaf
、 と) があります。バイナリ ツリーの仕組みに詳しくない場合は、このまま読み進めてください。バイナリ ツリーの仕組みを実際に知る必要はなく、これが何らかの方法で を格納することだけを知っていれば十分です。Branch
SBTree
String
また、両方のデータ コンストラクターが引数を取ることがわかります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
具体的な型から具体的な型へであると言えます。
まとめ
ここで少し立ち止まって、類似点に注目してください。
あデータコンストラクタ0以上の引数を取る「関数」である価値観そして新しい価値を返します。
あ型コンストラクタ0以上の引数を取る「関数」である種類そして新しいタイプを返します。
パラメータ付きのデータ コンストラクターは、値にわずかな変化を加えたい場合に便利です。パラメータに変化を持たせて、値を作成する人がどの引数を入れるかを決められるようにします。同様に、パラメータ付きの型コンストラクターは、型にわずかな変化を加えたい場合に便利です。パラメータに変化を持たせて、型を作成する人がどの引数を入れるかを決められるようにします。
ケーススタディ
ここで最後の追い込みとして、Maybe a
型について考えてみましょう。その定義は
data Maybe a = Nothing
| Just a
ここで、はMaybe
具体的な型を返す型コンストラクタです。はJust
値を返すデータコンストラクタです。はNothing
値を含むデータコンストラクタです。の型を見るとJust
、
Just :: a -> Maybe a
言い換えると、Just
は 型 の値を受け取りa
、 型 の値を返しますMaybe a
。 の種類を見るとMaybe
、
Maybe :: * -> *
つまり、Maybe
具体的な型を受け取り、具体的な型を返します。
もう一度!具体的な型と型コンストラクタ関数の違い。Maybe
実行しようとすると、sのリストを作成することはできません。
[] :: [Maybe]
エラーが発生します。ただしMaybe Int
、、またはのリストは作成できますMaybe a
。これは、Maybe
が型コンストラクタ関数であるのに対し、リストには具体的な型の値が含まれている必要があるためです。Maybe Int
およびMaybe a
は具体的な型です (または、必要に応じて、具体的な型を返す型コンストラクタ関数の呼び出しです)。