foldlWithKey のような関数を探していますが、モナドにカプセル化されています。
タイプがあると思います
Monad m => (a -> k -> b -> m a) -> a -> Map k b -> m a
しかし、Hoogle は私にそのタイプのものを何も与えてくれません。
foldlWithKey
あなたが望むものにすでに非常に近いです。専門化すると、モナドにカプセル化された値を操作する何かが得a
られます。m a
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 -^ -}
m a
と で不要な 2 つの を>>=
取り除くことができますreturn
。
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が>>=
左に深くネストされています。多くの (しかしすべてではない!) モナドでは、これにより non-strict を使用した場合と同様のスタックブローアップが発生する可能性がありますfoldl
。>>=
そこで、代わりに s を右にネストする別の解決策を提示します。このようなモナドIO
では、アクションが実行されたときにマップから遅延して構築および消費できるようにする必要があります。
この解決策は、最終的に開始値を消費するモナド関数を構築するために右折り畳みを使用するため、おそらく少しトリッキーです。少なくとも、タイプを正しくするのに苦労しました。
キーの処理を除いて、これは基本的に で使用されるメソッドと同じ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