2012-04-04 9 views
5

Ich glaube, ich bin ein grundlegendes Verständnis von Monade Transformatoren fehlen, weil ich mir diesen Code zu schreiben gefunden:Aufzug Fehlerwert ErrorT Monade Transformator

import Control.Monad.Identity 
import Control.Monad.Error 

liftError :: Either String Int -> ErrorT String Identity Int 
liftError x = do case x of 
        Right val -> return val 
        Left err -> throwError err 

gateway :: Bool -> ErrorT String Identity Int 
gateway = liftError . inner 

inner :: Bool -> Either String Int 
inner True = return 5 
inner False = throwError "test" 

Das funktioniert zwar, glaube ich, dass dies mehr getan werden könnte, elegant. Insbesondere suche ich nach einem Ersatz von liftError, den ich meiner Meinung nach nicht für mich definieren müsste.

Was wäre der einfachste Weg, gateway und inner zusammen zu arbeiten, ohne ihren Typ zu ändern?

Antwort

6

Wenn Sie nur die Typen ein wenig ändern, müssen Sie überhaupt nicht heben.

{-# LANGUAGE FlexibleContexts #-} 

gateway :: Bool -> ErrorT String Identity Int 
gateway = inner 

inner :: MonadError String m => Bool -> m Int 
inner True = return 5 
inner False = throwError "test" 

MonadError hat beide Instanzen für ErrorT und Either, so dass diese Art und Weise können Sie inner als beides.

+0

Okay, um genauer zu sein, muss ich eine manuelle Hebefunktion schreiben, wenn ich die Typen so lassen möchte, wie sie sind? Dies ist nur für mein Verständnis. BTW leider kann ich heute nicht mehr wählen:/Du bekommst morgen die Abstimmung :) –

+1

Ohne die Typen zu ändern, kannst du 'ErrorT' verwenden. Rückgabe an Stelle Ihrer "liftError" -Funktion. Sie könnten auch die allgemeinere Version intern verwenden und nur eine Kopie von "inner" mit dem eingeschränkten Typ verfügbar machen. – hammar

+0

Das 'ErrorT. Rückkehr war genau das, was ich suchte. Wie ich bereits erwähnt habe, hat das nichts mit irgendeinem echten Code zu tun, ich möchte nur das Konzept der Monade-Transformatoren verstehen :) –