Ich habe mehrere State
Monadenaktionen. Einige der Aktionen treffen Entscheidungen basierend auf dem aktuellen Zustand und andere Eingaben erzeugen optional das Ergebnis. Die zwei Arten von Aktionen rufen einander auf.Komponieren von Status- und Statustransformatoraktionen
Ich habe diese beiden Aktionstypen mit State
und StateT Maybe
modelliert. Das folgende (konstruierte) Beispiel zeigt meinen derzeitigen Ansatz.
{-# LANGUAGE MultiWayIf #-}
import Control.Monad (guard)
import Control.Monad.Identity (runIdentity)
import Control.Monad.Trans.State
type Producer = Int -> State [Int] Int
type MaybeProducer = Int -> StateT [Int] Maybe Int
produce :: Producer
produce n
| n <= 0 = return 0
| otherwise = do accum <- get
let mRes = runStateT (maybeProduce n) accum
if | Just res <- mRes -> StateT $ const (return res)
| otherwise -> do res <- produce (n - 1)
return $ res + n
maybeProduce :: MaybeProducer
maybeProduce n = do guard $ odd n
modify (n:)
mapStateT (return . runIdentity) $
do res <- produce (n - 1)
return $ res + n
Ich habe herausgerechnet, die Kontrollen von den Aktionen zu trennen (so sie in einfache staatlichen Aktionen verwandeln), weil die Prüfung selbst sehr beteiligt ist (80% der Arbeit) und stelle die Bindungen in der Aktion benötigt. Ich möchte nicht die State
Aktionen zu StateT Maybe
entweder fördern, weil es ein ungenaues Modell darstellt.
Gibt es einen besseren oder eleganeren Weg, den ich vermisse? Insbesondere mag ich nicht die mapStateT
/runStateT
Duo, aber es scheint notwendig.
PS: Ich weiß, dass das Beispiel ist eigentlich ein Writer
, aber ich verwendet State
besser, um den realen Fall
'mapStateT' ist völlig in Ordnung, IMO. Ich würde nur "Nur" verwenden. RunIdentity' als Argument. – arrowd
Etwa die gleiche Frage (obwohl mehr theoretisch): http://StackOverflow.com/Questions/4138671/Combining-Statet-and-State-Monads – gcnew