このように「バインド」関数を定義すると、次のようになります。
(>>=) :: M a -> (a -> M' b) -> M' b
結果を新しいモナドタイプにしたい場合、または同じモナドを使用する必要があるが、以前と同じモナドボックスにbを使用する必要がある場合、この定義は役に立ちますか?
コメントで述べたように、そのような操作は一般的なモナド(例えばM = IO
、M' = Maybe
)に対して安全に定義できるとは思いません。
ただし、Mが安全にM'に変換できる場合、このバインドは次のように定義できます。
convert :: M1 a -> M2 a
...
(>>=*) :: M1 a -> (a -> M2 b) -> M2 b
x >>=* f = convert x >>= f
そして逆に、
convert x = x >>=* return
このような安全な変換方法のいくつかは、maybeToList
(多分→[])、listToMaybe
([]→多分)、stToIO
(ST RealWorld→IO)、...convert
どのモナドにも一般的な方法がないことに注意してください。
その定義は役に立たないだけでなく、コードの将来の読者を深刻に混乱させるでしょう。なぜなら、それはそれに対する使用のすべての期待を破るからです。
たとえば、MとM'の両方がモナドであると想定されていますか?もしそうなら、それらはどのように定義されていますか?覚えておいてください:の定義>>=
はモナドの定義の一部であり、他のモナドを使用する関数を定義するためにどこでも使用されます-それ以外のすべての関数return
とfail
それ自体。
また、使用するMとM'を選択することはできますか、それともコンピューターを使用しますか?もしそうなら、どのように選択しますか?それは任意の2つのモナドインスタンスで機能しますか、それとも必要なモナドのサブセットがありますか?またはMの選択がM'の選択を決定しますか?
あなたが書いたような関数を作ることは可能ですが、それは確かにそれよりもはるかに複雑であり、あなたの関数を服>>=
に詰め込もうとすると、誤解を招き、残酷で、潜在的に悲惨なことになります。>>=
これは複雑な作業になる可能性がありますが、状況によっては実行可能です。基本的に、それらが内部で見ることができるモナド(Maybe
またはあなたが書いたモナドなど)である場合、そのような操作を定義できます。
Monad
(GHCで)時々非常に便利なことの1つは、クラスを独自のクラスに置き換えることです。定義した場合でも、表記return, >>=, fail
を使用できます。do
これがあなたが望むもののようなかもしれない例です:
class Compose s t where
type Comp s t
class Monad m where
return :: a -> m s a
fail :: String -> m a
(>>=) :: (Compose s t) => m s a -> (a -> m t b) -> m (Comp s t) b
(>>) :: (Compose s t) => m s a -> m t b -> m (Comp s t) b
m >> m' = m >>= \_ -> m'
次に、定義したインスタンスに基づいて、バインド演算子を使用してシーケンスできるタイプを制御できCompose
ます。当然、必要になることがよくありますがComp s s = s
、これを使用して、あらゆる種類のクレイジーなものを定義することもできます。
たとえば、モナドにいくつかの操作があり、他の操作を絶対に実行できない場合があります。それを静的に強制したいですか?空のデータ型を定義し、data Terminal
のインスタンスを提供しませんCompose Terminal t
。
Maybe
このアプローチは、(たとえば)からに移調するのには適していませんIO
が、実行していることに関するタイプレベルのデータを運ぶために使用できます。
モナドを本当に変更したい場合は、上記のクラス定義を次のように変更できます。
class Compose m n where
type Comp m n
(>>=*) :: m a -> (a -> n b) -> (Compose m n) b
class Monad m where
return :: a -> m a
fail :: String -> m a
(>>=) :: Compose m n => m a -> (a -> n b) -> (Compose m n) b
m >>= f = m >>=* f
(>>) :: Compose m n => m a -> (n b) -> (Compose m n) b
m >> n = m >>=* \_ -> n
私は前者のスタイルを有用な目的に使用しましたが、この後者のアイデアは特定の状況でも役立つ可能性があると思います。
Olegのこのサンプルをご覧になることをお勧めします:http://okmij.org/ftp/Computation/monads.html#param-monad