1. ホーム
  2. haskell

[解決済み] Haskell型とデータコンストラクタ

2022-06-24 11:16:32

質問

私はHaskellを learnyouahaskell.comから学んでいます。 . 私は型コンストラクタとデータコンストラクタを理解するのに苦労しています。たとえば、私はこの違いをよく理解していません。

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 ) は、3つの状態になることができる型です。 Blue , Green または Red . しかし、これは私が最初の2つの例を理解する方法と矛盾しています:それは、型 Car は一つの状態にしかなり得ないということでしょうか。 Car を構築するために様々なパラメータを取ることができるのでしょうか?もしそうなら、2番目の例はどのように適合するのでしょうか?

本質的に、私は上記の3つのコード例/構造を統一する説明を探しています。

どのように解決するのですか?

data 宣言では 型コンストラクタ は等号の左側にあるものです。その データコンストラクタ は等号の右側にあるものです。型が必要な場合はタイプコンストラクタを使用し、値が必要な場合はデータコンストラクタを使用します。

データコンストラクタ

物事を簡単にするために、色を表す型の例から始めましょう。

data Colour = Red | Green | Blue

ここでは、3つのデータコンストラクタを用意しています。 Colour は型、そして Green は型の値を含むコンストラクタです。 Colour . 同様に RedBlue の値を構築するコンストラクタです。 Colour . しかし、我々はそれをスパイスにすることを想像することができました

data Colour = RGB Int Int Int

まだ、型だけの Colour という型があるだけですが RGB は値ではありません。これは3つのIntsを取る関数で を返す を返す関数です。 RGB は型を持っています。

RGB :: Int -> Int -> Int -> Colour

RGB はデータコンストラクタであり、いくつかの を引数として取り、それを使って新しい値を構築する関数です。オブジェクト指向プログラミングをしたことがある人なら、このことを認識できるはずです。オブジェクト指向では、コンストラクタもいくつかの値を引数として取り、新しい値を返します。

この場合、もし RGB を適用すると、色の値が得られます。

Prelude> RGB 12 92 27
#0c5c1b

私たちは 値を構築した 型の Colour をデータコンストラクタの適用により構築します。データコンストラクタは、変数のように値を含むか、他の値を引数として受け取り、新しい . もしあなたが以前にプログラミングをしたことがあるなら、このコンセプトはそれほど奇妙なものではないはずです。

インターミッション

もし、バイナリツリーを構築して String を格納するためにバイナリツリーを構築したい場合、次のようなことを想像してみてください。

data SBTree = Leaf String
            | Branch String SBTree SBTree

ここで見るのは、型 SBTree という型であり、2つのデータコンストラクタを含んでいます。言い換えれば、2つの関数(すなわち LeafBranch の値を構築します)。 SBTree 型の値を構築します。二分木がどのように機能するのかよく知らない人は、そのままお待ちください。バイナリツリーがどのように機能するかは知らなくても大丈夫です。 String を何らかの形で保存しているということだけです。

また、どちらのデータコンストラクタも String 引数を取ります。これはツリーに保存される文字列です。

しかし!もし私たちが、この他に Bool を格納したい場合は、新しいバイナリツリーを作成する必要があります。それは次のようなものです。

data BBTree = Leaf Bool
            | Branch Bool BBTree BBTree

タイプ・コンストラクタ

両方 SBTreeBBTree はタイプ・コンストラクタです。しかし、重大な問題があります。これらがいかに似ているかわかりますか?それは、本当にどこかにパラメータが欲しいというサインです。

だから、こうすればいいんです。

data BTree a = Leaf a
             | Branch a (BTree a) (BTree a)

ここで 型変数 a を型コンストラクタのパラメータとして宣言します。この宣言では BTree は関数になっています。これは を引数として取り、新しい .

ここで重要なのは 具体的な型 (例としては Int , [Char]Maybe Bool ) は、プログラムの中で値を割り当てることができる型であり、また 型コンストラクタ関数 という、値に代入できるように型を与える必要がある関数があります。値は決して "list"型である必要はありません。 である必要があるからです。 とする必要があるからです。同じ精神で、値は決して "バイナリツリー" 型にはなりません。 何か である必要があるからです。

で渡すと、例えば Bool を引数として BTree という型が返されます。 BTree Bool を格納する二分木である。 Bool s. 型変数のすべての出現箇所を置き換える a を型 Bool という型に変換すれば、それがどのように正しいか自分で確認することができます。

もし、あなたが望むなら、表示される BTree を関数として 種類

BTree :: * -> *

Kindsはタイプに似ています。 * は具体的な型を示すので BTree は具象型から具象型へということになります。

ラップアップする

ここで一歩下がって、類似点に注意してください。

  • A データコンストラクタ は、0個以上の を受け取り、新しい値を返します。

  • A 型コンストラクタ は、0個以上の を受け取り、新しい型を返します。

パラメータ付きのデータコンストラクタは、値にわずかなバリエーションが欲しい場合に便利です。それらのバリエーションをパラメータに置き、値を作成する人がどの引数を置くかを決定します。同じ意味で、パラメータ付きの型コンストラクタは、型にわずかなバリエーションが欲しい場合に格好のものです! 私たちはそれらのバリエーションをパラメータとして置き、型を作成する人に、彼らがどのような引数を置くかを決定させます。

ケーススタディ

ここでのホームストレッチとしては Maybe a 型を考えてみましょう。その定義は

data Maybe a = Nothing
             | Just a

ここで Maybe は具象型を返すタイプ・コンストラクタです。 Just はデータコンストラクタで、値を返します。 Nothing は値を含むデータコンストラクタです。の型を見てみると Just の型を見ると、次のようになります。

Just :: a -> Maybe a

言い換えると Justa 型の値を取り、型の Maybe a . の種類を見ると Maybe の種類を見ると、次のようになります。

Maybe :: * -> *

言い換えると Maybe は具象型を取り、具象型を返します。

もう一回! 具象型と型コンストラクタ関数の違いです。のリストを作成することはできません。 Maybe を実行しようとすると

[] :: [Maybe]

のようにすると、エラーが発生します。しかし Maybe Int のリスト、または Maybe a . それは Maybe は型コンストラクタ関数ですが、リストは具象型の値を含む必要があるからです。 Maybe IntMaybe a は具象型です(必要であれば、具象型を返す型コンストラクタ関数の呼び出しでもかまいません)。