型と型クラス
9.2 代数的データ型
再帰的な型について
う〜ん、ちょっと難しい。。。一回読んだだけでは理解出来なかった。
細かく読み解いていこう。
本文中にあった例をそのまま使わせていただくと、
data Stack a = Empty | Push a (Stack a)
という型宣言。
data Stack a =
の部分は問題ないです。
「Stack」は型コンストラクタで、「a」はその引数(型!)。
問題は後半部です。
Empty | Push a (Stack a)
「Empty」は何?ということなんだけど、Preludeの中を探しても、そんな定義見つからない。
そうなんです、「Empty」は引数なしのデータコンストラクタなんです。
「|」は先日勉強した共用体スタイルの型宣言演算子(っていうの?)ですね。
そして一番問題なのが、「Push a (Stack a)」です。
この中を分解してみます。
前半部分の「Push a」。これはデータコンストラクタですね。
引数に型コンストラクタStackの引数を使っています。つまり「a」は任意の型なわけです。
後半部分の「(Stack a)」。これはデータコンストラクタ「Push」の第二引数です。
つまり、データコンストラクタ「Push」の第二引数には、(Stack a)という型を指定出来るのです。
う〜ん、ここ!ここが分かりにくいんです。
本当に簡易的な感じで書いてみると…
Stack a = Empty | Push a (Stack a) Stack a = Empty | Push a (Empty | Push a (Stack a) Stack a = Empty | Push a (Empty | Push a (Empty | Push a (Stack a))) Stack a = Empty | Push a (Empty | Push a (Empty | Push a (Empty | Push a (Stack a)))) -- 続く続く…
となるわけです。じゃぁ、この定義、いつまで続くのか?
それは「Stack a」が「Empty」になるまで続きます。
なんか見たことあるなぁ、と思います。
そうです、map関数の定義とまるっきり同じノリなんですよね。
map関数の定義はこんな感じでした。
map :: (a -> b) -> [a] -> [b] map f [] = [] map f (x:xs) = f x : map f (xs)
map関数の第二引数が「[]」になるまで展開されるわけですね。
最後に(Stack a)型を使っていろいろ遊んでみました。
main = do print $ isEmpty st1 print $ top st1 print $ isEmpty $ pop $ pop $ pop $ pop st1 data Stack a = Empty | Push a (Stack a) isEmpty :: Stack a -> Bool isEmpty Empty = True isEmpty (Push _ _) = False top :: Stack a -> a -- top Empty = top (Push x _) = x pop :: Stack a -> Stack a pop (Push _ stk) = stk st1 :: Stack Char st1 = Push 'd' (Push 'c' (Push 'b' (Push 'a' (Empty))))
% ghc -o example3 example3.hs % ./example3 False 'd' True
う〜ん、top関数は引数がEmptyの時、何を返すべきなんだろう?
a型の何かを返さなきゃいけないんだけど…。
上の例ではパターンマッチングしてないので、ghcのオプション「-W」は外してます。。。