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という結果とともに計算が成功したことを示しています。