Lassen Sie uns sagen, dass wir einen Stapel von Monaden mit einem Zustand Monade Transformator als Außen meisten Transformator wie diese haben:Staat Monaden: Der Übergang von einem Zustand Typ in einen anderen
-- | SEWT: Composition of State . Except . Writer monad transformers in that
-- order where Writer is the innermost transformer.
-- the form of the computation is: s -> (Either e (a, s), w)
newtype SEWT s e w m a = SEWT {
_runSEWT :: StateT s (ExceptT e (WriterT w m)) a }
deriving (Functor, Applicative, Monad,
MonadState s, MonadError e, MonadWriter w)
-- | 'runSEWT': runs a 'SEWT' computation given an initial state.
runSEWT :: SEWT s e w m a -> s -> m (Either e (a, s), w)
runSEWT ev e = runWriterT $ runExceptT $ runStateT (_runSEWT ev) e
Wir dann tun wollen, in einigen Formular: SEWT s e w m a -> s -> SEWT t e w m a
. Dies ist natürlich nicht möglich mit (>>=)
oder einem do
Block, da eine Zustandsmonade mit s
als Zustand nicht die gleiche Monade wie eine mit t
ist.
dann kann ich so etwas wie dies heraufbeschwören:
-- | 'sewtTransition': transitions between one 'SEWT' computation with state s,
-- to another with state s. The current state and result of the given
-- computation is given to a mapping function that must produce the next
-- computation. The initial state must also be passed as the last parameter.
transitionState :: (Monad m, Monoid w) => ((a, s) -> SEWT t e w m a)
-> m (SEWT s e w m a) -> s -> m (SEWT t e w m a)
transitionState _trans _comp _init = do
(res, logs) <- _comp >>= flip runSEWT _init
return $ do tell logs
case res of Left fail -> throwError fail
Right succ -> _trans succ
-- 'withState': behaves like 'transitionState' but ignores the state of
-- the first computation.
withState :: (Monad m, Monoid w)
=> m (SEWT s e w m a) -> s -> m (SEWT t e w m a)
withState = transitionState $ return . fst
Aber gibt es vielleicht eine elegantere und allgemeine Art und Weise von einem Zustand Typ in einen anderen zu bewegen?
Ich bin sowohl an Lösungen interessiert, bei denen die zweite Berechnung nicht vom Endzustand (nur das Ergebnis) der ersten Berechnung abhängt, als auch davon, wo sie ist.
Edit1: Verbesserte Übergangsfunktionen:
transSEWT :: Functor m => (((a, y), x) -> (a, y)) -> SEWT x e w m a -> x -> SEWT y e w m a
transSEWT f x_c x_i = SEWT $ StateT $ \y_i -> ExceptT . WriterT $
first ((\(a, x_f) -> f ((a, y_i), x_f)) <$>) <$> runSEWT x_c x_i
changeSEWT :: Functor m => SEWT x e w m a -> x -> SEWT y e w m a
changeSEWT = transSEWT fst
transS :: Monad m => (((a, y), x) -> (a, y)) -> StateT x m a -> x -> StateT y m a
transS f x_c x_i = StateT $ \y_i -> do (a, x_f) <- runStateT x_c x_i
return $ f ((a, y_i), x_f)
changeS :: Monad m => StateT x m a -> x -> StateT y m a
changeS = transS fst
Verknüpfung zusammen mit anderer Frage: http://stackoverflow.com/questions/28690448/what-is-indexed-monad – Centril