みどりねこ日記

よくわからないけど、頑張りますよ。

Haskellモナドトランスフォーマー(6)

Maybeトランスフォーマーのデータ型を宣言するところから始めましょう。MaybeTコンストラクタはひとつ引数を取ります。トランスフォーマーは、元のモナドと同じデータを取るので、newtypeキーワードを使用することにします。dataキーワードを使ってもいいのですが、必要のない負荷がかかるのでやめておきましょう。

newtype MaybeT m a = MaybeT { runMaybeT :: m (Maybe a) }

最初は戸惑うかもしれませんが、見た目ほど複雑でもないです。MaybeTのコンストラクタは、型m (Maybe a)である値をひとつ引数に取ります。ただそれだけです。このレコードの部分はただの糖衣構文で、MaybeTがレコードのように見ることができるというのと、runMaybeTを呼ぶことで引数にとった値を取得できます。
わかりやすく考えるなら、モナドトランスフォーマーをサンドイッチとして考えましょう。サンドイッチの下が元のモナド(ここではMaybe)、中身が「内なるモナド」m、そして一番上がモナドトランスフォーマーMaybeTです。関数runMaybeTの存在意義は、この一番上のモナドトランスフォーマーMaybeTを取り除くことです。runMaybeTの型は(MaybeT m a) -> m (Maybe a)です。

改めて言いますが、モナドトランスフォーマー自身もモナドです。MaybeTモナドの実装の一部が下にあります。この実装を見れば、元のモナドであるMaybeがいかにシンプルな実装であるかがわかりと思います。

Maybe
instance Monad Maybe where
	b_ v >>= f = case b_v of
		Nothing -> Nothing
		Just v -> f v
MaybeT
instance (Monad m) => Monad (MaybeT m) where
	tmb_v >>= f =
		MaybeT $ runMaybeT tmb_v
			>>= ¥b_v -> case b_v of
				Nothing -> return Nothing
				Just v -> runMaybeT $ f v

MaybeTの実装がMaybeのbindの実装に似ていると気づくかもしれません(ただし例外処理多し)。この余分な実装がモナドのサンドイッチから2つの層を取り出すために必要な部分です。