Haskell 型とデータコンストラクタ 質問する

Haskell 型とデータコンストラクタ 質問する

私は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) は、BlueGreenまたは の3 つの状態をとることができる型Redです。しかし、これは最初の 2 つの例の理解と矛盾しています。つまり、型はCar1 つの状態、つまり のみをとることができ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 では、コンストラクタも値を引数として受け取り、新しい値を返します。

この場合、RGB3 つの値に適用すると、色の値が得られます。

Prelude> RGB 12 92 27
#0c5c1b

我々は持っています価値を構築したデータコンストラクタを適用することで、型を定義できますColour。データコンストラクタは、変数のように値を格納するか、他の値を引数として受け取り、新しい型を作成します。価値これまでにプログラミングを経験したことがある人にとって、この概念はそれほど奇妙ではないはずです。

休憩

sを格納するためのバイナリツリーを構築したい場合はString、次のようなことを想像できます。

data SBTree = Leaf String
            | Branch String SBTree SBTree

ここで見られるのは、2 つのデータ コンストラクターを含む型ですSBTree。言い換えると、型の値を構築する2 つの関数 (つまりLeaf、 と) があります。バイナリ ツリーの仕組みに詳しくない場合は、このまま読み進めてください。バイナリ ツリーの仕組みを実際に知る必要はなく、これが何らかの方法で を格納することだけを知っていれば十分です。BranchSBTreeString

また、両方のデータ コンストラクターが引数を取ることがわかります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 BoolBoolaBool

必要に応じて、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は具体的な型です (または、必要に応じて、具体的な型を返す型コンストラクタ関数の呼び出しです)。

おすすめ記事