@ Cirdec Lösung funktioniert sicher, aber es hat ein mögliches Problem: Er nistet >>=
tief nach links s. Für viele (aber nicht alle!) Monaden kann dies einen Stapelvergrößerungseffekt ergeben, ähnlich wie bei Verwendung nicht-strikter foldl
. Also werde ich eine andere Lösung vorstellen, die stattdessen s nach rechts nistet. Für Monaden wie IO
sollte dies ermöglichen, dass die Aktion aus der Karte, wenn sie ausgeführt wird, träge konstruiert und konsumiert wird.
Diese Lösung ist wahrscheinlich etwas kniffliger, da sie eine richtige Falte verwendet, um die monadische Funktion aufzubauen, die schließlich den Startwert verbraucht. Zumindest hatte ich Schwierigkeiten, die Typen richtig zu machen.
Mit Ausnahme der Tastenbehandlung ist dies im Wesentlichen die gleiche Methode wie von 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
Äquivalent könnte man nicht einfach die Monade in 'ContT' für nur diese Funktion wickeln? – luqui
@luqui Ich denke nicht, dass das ziemlich äquivalent ist, mit einer linken Falte würden Sie immer noch die gesamte links-verschachtelte Aktion aufbauen, bevor 'ContT' es konvertieren könnte. Insbesondere kann es beim Konsum nicht so faul sein. –