このブログ記事では、Haskellにおいて重要なデータ型の定義方法について紹介しています。

データ型
私たちは、リスト、Bool
、String
、Integer
のような多くの事前に定義されたデータ型を見てきましたが、
自分自身でデータ型を定義することもできます。Bool
がどのように定義されているかを見て、新しいデータ型の定義方法を理解しましょう。
--- 新しいデータ型の定義
data Name =
Constructor1 <args> | Constructor2 <args> ...
--- Name: 新しいデータ型の名前
--- Constructor 1,2,...: 値コンストラクタ
--- <args>: コンストラクタの引数
data Bool = True | False
Bool
はデータ型であり、True
とFalse
は値コンストラクタです。値コンストラクタとは0個以上のパラメータ/引数を取り、データ型の値を返す関数を指します。
True
とFalse
の場合、パラメータを取らないので、それ自体がBool
型の値となります。
コンストラクタが0個以上のパラメータを取る関数であるため、次のようなこともできます。
data Calculation =
Add Int Int | Subtract Int Int | Multiply Int Int | Divide Int Int
Calculation
のすべてのコンストラクタはInt
型の2つの値を取り、Calculation
型の値を返します。GHCiで
コマンドを使ってコンストラクタの型を見てみましょう。
ghci> :t Add
Add :: Int -> Int -> Calculation
ghci> :t Subtract
Add :: Int -> Int -> Calculation
上記のように、値コンストラクタが関数であることがわかりますので、次のようなこともできます。
map (Add 1) [1,2,3] --- Output: [Add 1 1, Add 1 2, Add 1 3]
Calculation
データ型とそのコンストラクタは、次のようにパターンマッチングに使用できます。
calc :: Calculation -> Int
calc (Add x y) = x + y
calc (Subtract x y) = x - y
calc (Multiply x y) = x * y
calc (Divide x y) = div x y
再帰的データ型
Haskellでは、再帰を愛することを学ぶ必要があります。値コンストラクタは再帰的に、 自分の型の値を取り、それによって新しい値を作ることができます。いくつかの例を見て理解してみましょう。
data PeaNum =
Succ PeaNum | Zero
data Tree a =
Leaf | Node (Tree a) a (Tree a)
PeaNum
とTree
の両方には、引数を持たない値コンストラクタ(Zero
とLeaf
)と、自分の型の値を引数として取る値コンストラクタがあります。
これにより、より柔軟なデータ型を作成できます。ここで、Tree
にはその定義に型変数a
があることに注意してください。
データ型を通して引数の型を1つに限定したいが、使用する型を指定したくない場合は、Tree
のように定義に型変数を入れれば良いです。
これらの再帰的データ型をどのように使用できるのでしょうか?基本的には通常のデータ型と同じです。
--- 変数fiveにPeaNumの値を定義
five = Succ $ Succ $ Succ $ Succ $ Succ Zero
--- PeaNumのインクリメント
incr :: PeaNum -> PeaNum
incr = Succ --- 部分適用関数
--- PeaNumのデクリメント
decr :: PeaNum -> PeaNum
decr (Succ n) = n --- Succの分解
--- 2つのPeaNumを加算
add :: PeaNum -> PeaNum -> PeaNum
add Zero n = n
add (Succ m) n = Succ $ add m n --- Succの分解と$による構文
--- リスト内のPeaNumの合計を取得
sumPeaNums :: [PeaNum] -> PeaNum
sumPeaNums [] = Zero
sumPeaNums (x:xs) = add x $ sumPeaNums xs --- 上記のadd関数を使用
--- Intへの変換
count :: PeaNum -> Int
count Zero = 0
count (Succ n) = 1 + count n
Haskellのデータ型に関するルールは他にもたくさんありますが、今回はこれで終わりにしましょう。
クイズ
この記事では、学習した内容を確認するためのクイズを設けます。記事のメイン部分を読んだ後に、ぜひ自分で問題を解いてみることを強くお勧めします。各問題をクリックすると答えが表示されます。
リソース
- Philipp, Hagenlocher. 2020. Haskell for Imperative Programmers #10 - Datatypes. YouTube.
- NA. Making Our Own Types and Typeclasses. Learn You a Haskell for Great Good.