在 State monad 中有条件地更新地图的简洁方法
Concise way to conditionally update map in State monad
下面是来自 an answer regarding memoization 的代码,显示了状态 monad 中使用的记忆函数,如果键不在映射中,状态将使用传递的函数的结果进行更新。
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:感觉非常必要,每行并没有那么多。
有没有办法以更 concise/functional 的方式执行上述操作?我查看了 http://hackage.haskell.org/package/transformers-0.5.4.0/docs/Control-Monad-Trans-State-Lazy.html#v:state 上可用的函数,但似乎没什么用。
我认为你的代码是函数式的,但你可以稍微简化一下。
myMemo f x = maybe work return =<< gets (Map.lookup x)
where
work = do
y <- f x
modify $ Map.insert x y
return y
这是使用 mapState
以及来自 的 >>=
和 maybe
的替代方案,它避免了所有的符号
myMemo f x = gets (Map.lookup x) >>= maybe y' return
where
y' = mapState (\(y, map) -> (y, Map.insert x y map)) $ f x
这是在 基础上扩展的替代方案,使用更多 >>=
避免了所有 do 表示法
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)
这是在 基础上扩展的替代方案,本质上是对 do-notation
进行去糖处理
myMemo f x = gets (Map.lookup x) >>= maybe y' return
where
y' = f x >>= \y -> modify (Map.insert x y) >> return y
下面是来自 an answer regarding memoization 的代码,显示了状态 monad 中使用的记忆函数,如果键不在映射中,状态将使用传递的函数的结果进行更新。
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:感觉非常必要,每行并没有那么多。
有没有办法以更 concise/functional 的方式执行上述操作?我查看了 http://hackage.haskell.org/package/transformers-0.5.4.0/docs/Control-Monad-Trans-State-Lazy.html#v:state 上可用的函数,但似乎没什么用。
我认为你的代码是函数式的,但你可以稍微简化一下。
myMemo f x = maybe work return =<< gets (Map.lookup x)
where
work = do
y <- f x
modify $ Map.insert x y
return y
这是使用 mapState
以及来自 >>=
和 maybe
的替代方案,它避免了所有的符号
myMemo f x = gets (Map.lookup x) >>= maybe y' return
where
y' = mapState (\(y, map) -> (y, Map.insert x y map)) $ f x
这是在 >>=
避免了所有 do 表示法
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)
这是在
myMemo f x = gets (Map.lookup x) >>= maybe y' return
where
y' = f x >>= \y -> modify (Map.insert x y) >> return y