monad 中的 foldlWithKey
foldlWithKey in monad
我正在寻找类似 foldlWithKey 的函数,但封装在 monad 中。
我希望它有类型
Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a
但是 Hoogle 没有给我那种类型的任何东西。
foldlWithKey
已经很接近你想要的了。如果您将 a
专门化为 m a
,您将拥有对封装在 monad 中的值进行操作的东西。
foldlWithKey :: ( a -> k -> b -> a) -> a -> Map k b -> a
foldlWithKey :: (m a -> k -> b -> m a) -> m a -> Map k b -> m a
{- ^- you don't want these -^ -}
我们可以用 >>=
和 return
.
去掉你不想要的两个 m a
foldlWithKeyM :: Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a
foldlWithKeyM f acc = foldlWithKey f' (return acc)
where
f' ma k b = ma >>= \a -> f a k b
@Cirdec 的解决方案当然有效,但它有一个可能的问题:它嵌套 >>=
s 向左很深。对于许多(但不是全部!)monad,这会导致堆栈爆炸,类似于使用非严格的 foldl
。所以我将提出一个不同的解决方案,它向右嵌套 >>=
s。对于像 IO
这样的 monad,这应该允许在执行操作时从映射中懒惰地构造和使用操作。
这个解决方案可能有点棘手,因为它使用 right 折叠来构建最终将消耗起始值的 monadic 函数。至少我在正确设置类型时遇到了一些麻烦。
除了按键处理,这与 Data.Foldable.foldlM
使用的方法基本相同。
-- Pragma needed only to give f' a type signature for sanity. Getting it
-- right almost took a piece of mine until I remembered typed holes.
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Map
foldlWithKeyM
:: forall m a k b. Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a
foldlWithKeyM f start m = foldrWithKey f' return m $ start
where
f' :: k -> b -> (a -> m a) -> (a -> m a)
f' k b a2mb a = f a k b >>= a2mb
我正在寻找类似 foldlWithKey 的函数,但封装在 monad 中。
我希望它有类型
Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a
但是 Hoogle 没有给我那种类型的任何东西。
foldlWithKey
已经很接近你想要的了。如果您将 a
专门化为 m a
,您将拥有对封装在 monad 中的值进行操作的东西。
foldlWithKey :: ( a -> k -> b -> a) -> a -> Map k b -> a
foldlWithKey :: (m a -> k -> b -> m a) -> m a -> Map k b -> m a
{- ^- you don't want these -^ -}
我们可以用 >>=
和 return
.
m a
foldlWithKeyM :: Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a
foldlWithKeyM f acc = foldlWithKey f' (return acc)
where
f' ma k b = ma >>= \a -> f a k b
@Cirdec 的解决方案当然有效,但它有一个可能的问题:它嵌套 >>=
s 向左很深。对于许多(但不是全部!)monad,这会导致堆栈爆炸,类似于使用非严格的 foldl
。所以我将提出一个不同的解决方案,它向右嵌套 >>=
s。对于像 IO
这样的 monad,这应该允许在执行操作时从映射中懒惰地构造和使用操作。
这个解决方案可能有点棘手,因为它使用 right 折叠来构建最终将消耗起始值的 monadic 函数。至少我在正确设置类型时遇到了一些麻烦。
除了按键处理,这与 Data.Foldable.foldlM
使用的方法基本相同。
-- Pragma needed only to give f' a type signature for sanity. Getting it
-- right almost took a piece of mine until I remembered typed holes.
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Map
foldlWithKeyM
:: forall m a k b. Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a
foldlWithKeyM f start m = foldrWithKey f' return m $ start
where
f' :: k -> b -> (a -> m a) -> (a -> m a)
f' k b a2mb a = f a k b >>= a2mb