2011-02-11 44 views
7

我有一个在IntMap上运行的算法,我觉得这个算法最好能够表达出来。也就是说,我想说的是:是否存在Data.Map/Data.IntMap的monad实例?

  • 在地图中查找值X.
  • 如果它符合条件,请从地图中删除此值。
  • 循环直到地图中不存在更多值。

这将是相当琐碎来表达作为两行递归,但实际的算法是有点复杂,涉及多个查找和删除,所以我希望能够表达它do符号。

有没有一个标准的“国”般的单子,其中状态由Data.MapData.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定义我自己的状态单子,甚至得到尽可能使insertdelete工作,但有一点坚持了如何处理lookup。大多数情况下,我觉得这可能是某人已经解决的问题,但我无法在Hackage上找到它。

回答

21

是否有任何特别的原因要避免使用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,除了在main(并且使用不安全的函数)之外,你不会想要逃脱它。

所有你需要记住的是返回Maybe类型的任何状态动作只需提升到MaybeT构造函数。如果你想将IO状态改变为StateT。

+0

哇。谢谢。我真的需要习惯使用变压器。这个例子在展示如何实际使用它们方面有很大的帮助。所有monad教程都会向您展示如何从头开始构建,但很少会向您展示如何利用已有的功能。 – Steve 2011-02-12 04:39:01

相关问题