我有一个在IntMap上运行的算法,我觉得最好用强制表达。也就是说,我想说的是:
这表示为两行递归是相当简单的,但实际算法稍微复杂一些,涉及多次查找和删除,所以我希望能够在do
中表达它。符号
是否有一个标准的“州”式单子格,其中州由Data.Map
或Data.IntMap
表示,我可以在其中执行以下操作:
do
insert 5 20
(ma, mv) <- lookup 4
case mv of
Just v -> delete (fromJust ma)
Nothing -> return ()
老实说,我不确定如何最好地表达这一点......由于lookup
它似乎会从某种MaybeT IntMap m
堆栈中获益。
我尝试根据Data.IntMap
定义自己的状态monad做了一些工作,甚至可以使insert
和delete
工作,但有点困惑如何处理lookup
。大多数情况下,我觉得这可能是某人已经解决的问题,但我无法在Hackage上找到它。
答案 0 :(得分:22)
您是否有任何特殊原因要避免使用monad变压器?如果您从Hackage获得MaybeT包,您可以实现您想要的:
import Control.Monad
import Control.Monad.Maybe
import Control.Monad.State
import qualified Data.Map as Map
type MapM k v a = MaybeT (State (Map.Map k v)) a
lookupM k = MaybeT $ Map.lookup k `liftM` get
insertM k = modify . Map.insert k
deleteM k = modify $ Map.delete k
runMap m = (flip execState) m . runMaybeT
foo = runMap Map.empty $ do
insertM 5 20
v <- lookupM 4
deleteM v
当lookupM失败时,其余的计算失败。你可以随时输入和转义这些monad,这样你就可以在纯函数接口下隐藏它们,它只是你不应该从主要(和使用不安全的函数)中逃脱的IO monad。
所有你需要记住的是任何返回Maybe类型的状态动作只是提升到MaybeT构造函数中。如果你想做IO改变状态为StateT。