2017-09-11 2 views
1

Gegeben ist ein mtl Monadenstapel, z.B. ExceptT String (WriterT String (State s a)), wie kann ich die innere Zustands-Monade auswerten, ohne die äußeren Monaden auspacken zu müssen?EvalState in einem Monad-Transformatorstapel

have :: ExceptT String (WriterT String (State s)) a 
f :: State s a -> a 

want :: ExceptT String (WriterT String Identity) a 

Ich kann dies tun, indem runExceptT gefolgt von runWriterT und Umpacken die Ergebnisse danach ruft, aber es scheint, wie die falsche Art und Weise, dies zu erreichen.


Soweit ich versuchte, so etwas wie fmap oder ähnliches wird nicht funktionieren, weil der Stapel Monade Transformator als Gesamt Monade behandelt eigene drauf. Was ich brauche, ist eine Funktionalität auf „Split“ die Monade Transformator Stapel wie folgt aus:

split :: (MonadTrans s, Monad t) => (s t) a -> s (t a) 

Entweder habe ich diese Funktion nicht oder die Lösung funktioniert ganz anders gefunden.

+2

Sie können nicht. Alles, was ein Transformator hinzufügt, ist "lift :: m a -> t m a". Es gibt keinen generischen Weg, um das zu implementieren, was Sie gerade mit 'Monad' und' MonadTrans' machen wollen (die ganze Vorstellung von "laufenden" Dingen ist nicht einmal Teil des Monadetransformator-Konzepts). Sie können spezialisierte Funktionen wie in der Antwort haben, aber keine generische Lösung. – Cubic

Antwort

3

Der Ansatz, den einfachsten in diesem speziellen Fall scheint, ist die MFunctor Instanzen zu verwenden die ExceptT e und WriterT w Transformatoren:

import Control.Monad.Morph 

floop :: Monad m 
     => s 
     -> ExceptT e (WriterT w (StateT s m)) a 
     -> ExceptT e (WriterT w m) a 
floop s = hoist (hoist $ flip evalStateT s) 

Seit State s = StateT s Identity ist die leichte Verallgemeinerung oben unmittelbar.

+0

'hiist' war genau das, was ich suchte. – ThreeFx

5

Ich bin mir nicht bewusst, etwas so allgemein wie Ihre split, aber die map...T Funktionen könnten die explizite Manipulation verhindern:

have :: ExceptT String (WriterT String (State s)) a 
f :: State s a -> a 

want :: ExceptT String (WriterT String Identity) a 
want = mapExceptT (mapWriterT (return . f)) have 
Verwandte Themen