Set
、同様に[]
完全に定義されたモナド操作を持っています。問題は、値が制約を満たす必要があるため、制約なしOrd
で定義することは不可能です。同じ問題は、可能な値に対して何らかの制約を必要とする他の多くのデータ構造にも当てはまります。return
>>=
標準的なトリック ( haskell-cafe の投稿Set
で私に提案された) は、継続モナドにラップすることです。ContT
基になる型ファンクターに制約があるかどうかは気にしません。制約は、Set
s を継続に/からラップ/アンラップする場合にのみ必要になります。
import Control.Monad.Cont
import Data.Foldable (foldrM)
import Data.Set
setReturn :: a -> Set a
setReturn = singleton
setBind :: (Ord b) => Set a -> (a -> Set b) -> Set b
setBind set f = foldl' (\s -> union s . f) empty set
type SetM r a = ContT r Set a
fromSet :: (Ord r) => Set a -> SetM r a
fromSet = ContT . setBind
toSet :: SetM r r -> Set r
toSet c = runContT c setReturn
これは必要に応じて機能します。たとえば、引数を 1 増やすか、そのままにしておく非決定論的関数をシミュレートできます。
step :: (Ord r) => Int -> SetM r Int
step i = fromSet $ fromList [i, i + 1]
-- repeated application of step:
stepN :: Int -> Int -> Set Int
stepN times start = toSet $ foldrM ($) start (replicate times step)
確かに、stepN 5 0
利回りfromList [0,1,2,3,4,5]
. []
代わりにモナドを使用すると、次のようになります
[0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4,1,2,2,3,2,3,3,4,2,3,3,4,3,4,4,5]
代わりは。
問題は効率です。を呼び出すとstepN 20 0
、出力に数秒かかり、stepN 30 0
妥当な時間内に終了しません。Set.union
各モナド計算の後に実行するのではなく、すべての操作が最後に実行されることがわかります。その結果、指数関数的に多くSet
の が構築さunion
れ、最後にのみ編集されることになり、これはほとんどのタスクでは受け入れられません。
この構造を効率的にするために、それを回避する方法はありますか? 私は試しましたが、成功しませんでした。
(私は、カリー・ハワード同型とグリベンコの定理から、ある種の理論的限界があるのではないかとさえ思っています。グリベンコの定理は、任意の命題トートロジーφに対して、式¬¬φは直観論的論理で証明できると述べています。しかし、私は、証明の長さは (通常の形式で) 指数関数的に長くなる可能性があります. したがって, 計算を継続モナドにラップすると指数関数的に長くなる場合があるかもしれません?)