在State monad中有条件地更新地图的简明方法

时间:2017-06-13 07:31:59

标签: haskell functional-programming monads memoization

以下是来自an answer regarding memoization的代码,显示状态monad中使用的memoization函数,如果该键不在映射中,则使用传递函数的结果更新状态。

type MyMemo a b = State (Map.Map a b) b

myMemo :: Ord a => (a -> MyMemo a b) -> a -> MyMemo a b
myMemo f x = do
  map <- get
  case Map.lookup x map of
    Just y  -> return y
    Nothing -> do
      y <- f x
      modify $ \map' -> Map.insert x y map'
      return y

它看起来不像惯用的Haskell:它感觉非常迫切,并不是每行都有那么多。

有没有办法做到这一点,但更简洁/功能的风格?我已经浏览了http://hackage.haskell.org/package/transformers-0.5.4.0/docs/Control-Monad-Trans-State-Lazy.html#v:state处可用的功能,但似乎没有任何帮助。

4 个答案:

答案 0 :(得分:3)

我认为你的代码是功能样式的,但你可以简化它。

myMemo f x = maybe work return =<< gets (Map.lookup x)
  where
    work = do
        y <- f x
        modify $ Map.insert x y
        return y

答案 1 :(得分:0)

这是使用<h1 class="header-title">@Model.CollectionsManagementViewModels .First() .Title </h1> 以及https://stackoverflow.com/a/44515364/1319998mapState>>=的替代方法,可以避免所有的注释

maybe

答案 2 :(得分:0)

这是一种在https://stackoverflow.com/a/44515364/1319998上展开的替代方案,使用更多>>=来避免所有的记号

myMemo :: Ord a => (a -> MyMemo a b) -> a -> MyMemo a b
myMemo f x = gets (Map.lookup x) >>= maybe y' return
  where
    y' = f x >>= \y -> state $ \map -> (y, Map.insert x y map)

答案 3 :(得分:0)

这是一个可以扩展https://stackoverflow.com/a/44515364/1319998的替代方案,基本上可以解除附加费用

myMemo f x = gets (Map.lookup x) >>= maybe y' return
  where
    y' = f x >>= \y -> modify (Map.insert x y) >> return y