みどりねこ日記

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

Haskellのモナド3(1)

モナドについて学ぶうちに気づかれたかもしれませんが、どちらも計算結果の個数を表現するという意味でMaybeモナドとリストモナドは結構似ています。 すなわち、Maybeモナドを使用して計算が失敗する可能性(0個または1個の結果)を、リストモナドを使用して計算結果が0個以上の正しい結果を返す可能性(空リストが失敗、それ以外が正しい結果)を表現することが出来ます。

これらのモナドの計算を2つ与えられたとき、これらを結合するのも面白いかもしれません。例えば、正しい結果を”すべて”みつけたいとき、すなわち、2つの正しい結果としてのリストが与えられたとして、すべての正しい結果をみつけたいとき、単純にリストを結合すればいいですね。こういった形で結合できるということは、foldを使った折りたたみのときに”リストにとっての0”、つまり空リストを扱う上などで便利だったりします。

この2つの機能を型クラスとして用意します。

class Monad m => MonadPlus m where
	mzero :: m a
	mplus :: m a -> m a -> ma

Maybeモナドとリストモナドのインスタンス定義が以下になります。

instance MonadPlus [] where
	mzero = []
	mplus = (++)

instance MonadPlus Maybe where
	mzero = Nothing
	Nothing `mplus` Nothing = Nothing  -- 0+0=0
	Just x `mplus` Nothing = Just x  -- 1+0=1
	Nothing `mplus` Just x = Just x  -- 0+1=1
	Just x `mplus` Just y = Just x  -- 1+1=2、ただしMaybeモナドはひとつしか結果を取れないので2つ目のを無視する

もしControl.Monad.Errorをインポートした場合、(Either e)もインスタンスとなります。

instance (Err e) => MonadPlus (Either e) where
	mzero = Left noMsg
	Left _ `mplus` n = n
	Right x `mplus` _ = Right x

Either eはMaybeのように、「失敗するかもしれない計算」を表していますが、失敗した場合、計算の中にエラーメッセージを含めることが出来ます。一般的に、Left sはエラーメッセージsとともに計算が失敗したことを伝え、Right xはxという結果とともに計算が成功したことを示しています。