素人が代数的データ型について雑に考えてみる
どうも、鳥居です。今回はHaskellやOcamlなどの関数型言語に特有の代数的データ型について考えてみたいと思います。例によって超初心者が書き下した雑文なので多々到らない部分があると思いますがご了承ください(;'∀')
https://ja.wikipedia.org/wiki/代数的データ型
さて、この代数的データ型ですがwikipediaではこのように書いてあります。
「代数的データ型の値(データ)の感覚的な説明としては、引数で与えられた他のデータ型の値を、コンストラクタで包んだようなもの、である。」
…はて、何のことでしょうか…(@_@)
コンストラクタってあれですよね。Javaとかでクラスを作るときにフィールドの値を初期化するときとかに使うあれですよね。それでデータ型の値を包むっていうのは…どういう意味だ(+o+)
とりあえずHaskellで代数的データ型を宣言するときにどう書くのか見てみますか。
data Node = Leaf Integer | Branch Node Node
…うーん、分からん。
などと泣き言をのたまうのはやめてよくよくどういう意味なのか考えてみるとどうやら、
・まずある複数の型を表す抽象的で大きな型がある
・その型に含まれる型をその大きな型に代入(?)することで抽象的だったその大きな型の具体的な型が決定する
…感じみたいです(*_*;
うん、素人が雑に手を出すべきやつではなかったorz
まあ、もう少しだけ考えてみることにしますか。
上の書籍で記されているヴァリアント型(これも代数的データ型の一つのようです)の例を参考にしてひも解いてみたいと思います。
この本では代数的データ型を、
「作り方に複数の方法があるようなデータ(型)」
と定義しているようです。
例えば、「図形」という抽象的な型があるとします。
図形といえば、
・点
・円
・長方形
・正方形
などの種類がありますよね?
これらをそれぞれ別個の型として扱うよりも、まず大きく
・図形
と定義してから
・図形の点
・図形の円
・図形の長方形
・図形の正方形
とまとめたほうが、なんていうか、気持ちいい(?)ですよね?(何を言ってるんでしょう私は…)
そういったときに役立つのが代数的データ型となります。
Ocamlでの宣言方法を例にとると、
type figure=(*figure型の宣言*)
|Point(*点*)
|Circle of int(*円*)
|Rectangle of int * int(*長方形*)
|Square of int ;;(*正方形*)
といった感じに宣言します。具体的に値を生成するときは、
let c = Circle 3;;
と記述します。こうすることで
val c:figure(*cはfigure型*) = Circle (*cはCircle(円)である*) 3;;
といった感じで構築されます。…難しい('Д')
ここで先ほどのwikipediaの説明に戻ってみます。
「代数的データ型の値(データ)の感覚的な説明としては、引数で与えられた他のデータ型の値を、コンストラクタで包んだようなもの、である。」
上の例だと、「Circle」がどうやらコンストラクタで、「figure」が代数的データ型に相当しそうです。
じゃあ、3は…?
すみません。説明不足でしたね(:_;)
コンストラクタを定義したときの
of int
や
of int * int
は、大きさを決めるときに必要なものでした。円だと、
・int型の値一個を半径として引数にとって
・半径×半径×3.14
が大きさとして返されればいいですし、長方形だと
・int型の値二つを引数にとって
・縦×横
を大きさと返せばよいわけです。(本当に申し訳ございません。ここらへんは後で文章を推敲しますorz)
…ということは? そうですね。「引数で与えられた他のデータ型」が上での「3」に相当しそうです。(本当に回りくどくなってしまった)
さすがにこれ以上長ったらしく書くと収拾がつかなくなりそうなので今日はこの辺にしておきます。お見苦しい文章をお見せしてしまい本当にすみませんでした。機会があればもう少しだけ掘り下げてみたいと思います。
コメント