フリーモナドを使用して、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.Free
でControl.MonadPlus.Free不要なディストリビューションなし
は、Plus ms >>= f
f
はms
各モナド下Pure
リーフの各々に適用させます。これは、f
がそれが置き換えられる各Pure
リーフに対して異なる値を生成する可能性があるために必要です。
しかし、Plus ms >> g
で、g
はms
の葉のいずれかによって影響を受けるので、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
を使用するより良い方法がありますか?