2013-10-04 12 views
6

フリーモナドを使用して、ANDにマップされた>>=とANDにマップされたのPrologのようなAND/OR決定木を構築するためのEDSLを作成しようとしています。私はA AND (B OR C) AND (D OR E)のようなものを記述できるようにしたいが、私はこれを(A AND B AND D) OR (A AND B AND E) OR (A AND C AND D) OR (A AND C AND E)に変えることは望ましくない。結局のところ、ソルバーに対処させたい代替数の組合せ爆発を引き起こさずに、制約ソルバーでAND/ORノードを限定された制約に変換したいと考えています。 Control.MonadPlus.FreeControl.MonadPlus.Free不要なディストリビューションなし

は、Plus ms >>= ffms各モナド下Pureリーフの各々に適用させます。これは、fがそれが置き換えられる各Pureリーフに対して異なる値を生成する可能性があるために必要です。

しかし、Plus ms >> gで、gmsの葉のいずれかによって影響を受けるので、Plusの上にそれを配布することは不要と思われることはできません。試行錯誤

、私は新しいThenコンストラクタでControl.MonadPlus.Freeモナドを拡張することが分かっ:ここ

data Free f a = Pure a 
       | Free (f (Free f a)) 
       | Then [Free f()] (Free f a) 
       | Plus [Free f a] 

、新しいThenコンストラクタは、続いて値我々は無視モナドの順序を保持しています実際の価値をもたらす最終的なモナド。新しいMonadインスタンスは、次のようになります。Pure()Pure aを交換することにより

instance Functor f => Monad (Free f) where 
    return = Pure 

    Pure a >>= f = f a 
    Free fa >>= f = Free $ fmap (>>= f) fa 
    Then ms m >>= f = Then ms $ m >>= f 
    Plus ms >>= f = Plus $ map (>>= f) ms 

    Pure a >> mb = mb 
    Then ms ma >> mb = Then (ms ++ [ma >>= (const $ return())]) mb 
    ma >> mb = Then [] ma >> mb 

>>演算子「キャップ」既存の葉を、リストに頂いたモナドを追加し、新しいものと値モナドを置き換えます。私は新しいモナドに++を追加することの非効率性を認識していますが、fmapでチェーンの最後に新しいモナドをステッチするのは>>=と悪いと思います(そして、すべてを連続で書き換えることができます)。

これは妥当なことですか?これはモナド法に違反していますか(これは問題ですか?)、または既存のControl.Monad.Freeを使用するより良い方法がありますか?

答えて

2

私のoperationalパッケージを見てみるといいかもしれませんが、これは無料のモナドを取り上げたものです。

具体的には、BreadthFirstParsing.hsの例をご覧ください。それはmplus操作を備えているので、>>=ではなく、が自動的にそれに分配されます。これにより、パーサーコンビネータを広い意味で実装することができます。 Control.Monad.Freeに翻訳

、ポイントはあなたがファンクタ

data F b = MZero | MPlus b b 

を使用した場合、その後Free Fが自動的mplus>>=を配布することです。あなたは自動的に>>=を配布していませんMPlusのためのセマンティクスを実装したい場合は、代わりにファンクタ

data F b = MZero | forall a. MPlus (Free f a) (Free f a) (a -> b) 

を使用する必要があります。(これが私の運用ライブラリを無料のライブラリよりも好む主な理由です)