0

Betrachten Sie das folgende SnippetWillkürliche Monade Transformator Stapel in Variable vom Typ

import Control.Monad.Trans 
import Control.Monad.Trans.Except 
import Control.Monad.Trans.State 

newtype MyTransT m a = MyTransT (m a) 

foo :: (MonadTrans t, Monad (t (Either e))) => MyTransT (t (Either e)) a -> a 
foo = undefined 

bar :: MyTransT (StateT Int (Either e)) a 
bar = undefined 

baz :: MyTransT (StateT Int (StateT Int (Either e))) a 
baz = undefined 

x = foo bar -- works 

y = foo baz -- doesn't work 

Im Wesentlichen Ich versuche, eine Funktion zu erstellen, die einen Stapel Monade Transformators akzeptiert, mit der Ober- und Unterseite des Stapels angegeben, während der Mitte kann alles sein.

Nach meinem Kopf für eine Weile kratzen, warum foo baz mit Couldn't match type ‘StateT Int (Either e1)’ with ‘Either e0’ abgelehnt wurde, es kam schließlich zu mir, dass in diesem Fall war ich davon aus, dass tStateT Int (StateT Int) war das nicht nicht nur ein MonadTrans, es ist nicht richtig getippt/kinded.

Gibt es eine Möglichkeit, das zu erreichen, was ich versuche, oder ist es an der Zeit, einen anderen Ansatz zu wählen?

+0

Können Sie einige konkrete Beispiele dafür geben, wie Sie 'foo' in der Praxis anwenden können? – ErikR

+0

Stellen Sie sich vor Sie haben einen Typ 'T', der an einen Container vom Typ' V' mit Schlüsseln vom Typ 'K' gedacht werden kann. Stellen Sie sich nun vor, dass jedes 'V' ebenfalls diesem Muster folgt. Ich hätte gerne 'foo :: StateT V (t (Entweder e)) a -> StateT T (ReaderT K (t (Entweder e))) a '. Dies würde zustandsorientierte Operationen über "V" erfordern und sie in zustandsbehaftete Operationen über "T" bringen, die eine Umgebung mit "K" haben. Im Grunde eine Baumstruktur, die ich unendlich nach oben und unten verlängern kann, ohne den bestehenden Code zu ändern. – user2085282

+0

Konkrete Beispiele wären hier hilfreicher. Und zögern Sie nicht, es in Ihre Frage zu stellen, wo es leichter zu lesen ist. – ErikR

Antwort

0

Der Grund, warum foo baz nicht Prüfung nicht geben, weil die t kein Transformator über die Either e Monade ist - es ist ein Transformator über die StateT Int (Either e) Monade.

Hier ist, wie es analysiert wird:

baz :: MyTransT (StateT Int (StateT Int (Either e))) a 
        \________/ \_____________________/ 
         t   m     a 

Beachten Sie, dass m ist nicht der Form Either e.

Sie könnten einen neuen Transformator, z. StateTIntStateTInt und schreiben baz wie folgen aus:

baz :: MyTransT (StateTIntStateInt (Either e)) a 

und dann würde es Prüfung geben. Zum Beispiel:

type StateTIntStateTInt = StateT (Int,Int) 

baz' :: MyTransT (StateTIntStateTInt (Either e)) a 
baz' = undefined 

test = foo baz' 

Aber auch wenn Sie rund um die Art Fragen arbeite ich bezweifle, dass Sie gehen der Lage sein, die Funktion foo zu schreiben.

bar0 :: MyTransT (StateT Int (Either String)) Int 
bar0 = MyTransT $ lift $ Left "blather" 

Was Int Wert sollte foo bar0 Rückkehr: Überlegen Sie, was sollte für diesen speziellen Wert von bar zurückgegeben werden?

+0

Ich erkenne das und stelle es sogar in der Frage auf. Der Punkt war, dass 'foo' in der Lage sein sollte, einen willkürlichen Stapel von Transformatoren zu akzeptieren, daher ist es unwahrscheinlich, einen neuen Typ für jede Möglichkeit zu erstellen. Außerdem ist der Rückgabetyp von 'foo' ein Platzhalter, das Snippet dient nur dazu, das Problem zu demonstrieren. In der Realität würde "foo" einen Wert zurückgeben, der mit t (e) in Beziehung steht – user2085282