Haskell でユーザ定義のデータを簡単に作る方法
Haskell でユーザ定義のデータをきちんと使いこなせるためには、data, class, instance, deriving の4つのキーワードに習熟しておく必要がある。
そのためには、データの型名とは何かとか、コンストラクタとは何かとか、クラスとは何かとか、インスタンスは何かとか、クラスの関数のオーバロードはどうするかとか様々な知識が必要になってくる。Haskell に慣れてくれば、そういう知識を活用していろいろな工夫をすることができるだろが、初心者にとっては敷居が高い。
そこで、単にユーザ定義のデータ型を使いたいだけのときはどうすればいいかを考えてみた。それは、とりあえず、
data データ型の定義
deriving Show
とするだけだ。これで、大抵の用は足りる。
たとえば、二分木のデータ型で、葉の部分に整数型のデータを保持するデータ型を Btree という名前で定義してみる。Btree 型のデータは2種類のデータから構成されるとする。ひとつは整数値を保持する葉の部分を表す、Leaf Int 型で、もうひとつは木構造の節の部分を表す、Node Btree Btree 型だ。Leafの先には数字がぶら下がっており、Nodeの両端には Btree がぶら下がっているというイメージだ。
これを上に述べた方法で定義すると次のようになる。
data Btree = Leaf Int | Node Btree Btree
deriving Show
data というキーワードはデータ型を定義するから分かる。deriving と Show が分からないが、それは、後で Google 先生に尋ねることにして、今のところはお約束として意味を問わないことにする。
そうすると、
1^(2^3)
のような木構造は上の定義を使って、
sampletree = Node (Leaf 1) (Node (Leaf 2) (Leaf 3))
のように定義できる。そこで、次のようなファイル mydata.hs を作って ghci で実行してみる。
data Btree = Leaf Int | Node Btree Btree
deriving Show
sampletree = Node (Leaf 1) (Node (Leaf 2) (Leaf 3))
実行例
Prelude> :l mydata.hs 上の実行例で sampletree としてデータの内容を表示させるために deriving Show が必要だったのだ。テクニカルに表現すると、Btree型のデータ型に show 関数を適用させるためには、deriving キーワードでBtreeがShowクラスのインスタンスであることを宣言する必要があったのだ。要するに詳しいことはあとで勉強することにしてとりあえず、データ型の定義の末尾には deriving Show をつけるものだと覚えておけばいい。
二分木構造のデータを定義できるようになったのでこれを使うことを考える。この二分木を探索して、Leaf の部分に収められている整数値のデータを全て集めてリストにする関数 toList を定義してみよう。
まず、Btreeのデータが Leaf x なら、toList は [x] を返す。次にBtree のデータが Node x y 型の場合、toList は toList x と toList y を連結したものになる。従って toList の定義は次のようになる。
そこで、toList の定義を追加した mydata.hs は次のようになる。
随分簡単なプログラムだが、次のようにちゃんと動いてくれる。
そういうわけで、Haskellでユーザ定義のデータ型を使いたくなったら、
data データ型の定義 deriving Show
としておけば、とりあえずユーザ定義のデータ型を使ってみることができることがわかった。
ユーザ定義のデータ型を記述する
[1 of 1] Compiling Main ( mydata.hs, interpreted )
Ok, modules loaded: Main.
*Main> sampletree
Node (Leaf 1) (Node (Leaf 2) (Leaf 3))
ユーザ定義データ型を使う
toList (Leaf x) = [x]
toList (Node x y) = (toList x) ++ (toList y)
data Btree = Leaf Int | Node Btree Btree
deriving Show
sampletree = Node (Leaf 1) (Node (Leaf 2) (Leaf 3))
toList :: Btree -> [Int]
toList (Leaf x) = [x]
toList (Node x y) = (toList x) ++ (toList y)
*Main> :l mydata.hs
[1 of 1] Compiling Main ( mydata.hs, interpreted )
Ok, modules loaded: Main.
*Main> toList sampletree
[1,2,3]