J'ai de la difficulté à saisir les monars et les transformateurs monad. Je le exemple suivant artificiel (non compilable):Monades dans un contexte de transformateur monad
import Control.Monad
import Control.Monad.Error
import Control.Monad.Reader
data State = State Int Int Int
type Foo = ReaderT State IO
readEither :: String -> Either String Int
readEither s = let p = reads s
in case p of
[] -> throwError "Could not parse"
[(a, _)] -> return a
readEitherT :: IO (Either String Int)
readEitherT = let p s = reads s
in runErrorT $ do
l <- liftIO (getLine)
readEither l
foo :: Foo Int
foo = do
d <- liftIO $ readEitherT
case d of
Right dd -> return dd
Left em -> do
liftIO $ putStrLn em
return (-1)
bar :: Foo String
bar = do
liftIO $ getLine
defaultS = State 0 0 0
Si je copie la fonctionnalité de readEither à readEitherT, cela fonctionne, mais je un sentiment lancinant que je peux tirer parti de la puissance du readEither existant fonction, mais je ne peux pas comprendre comment. Si j'essaie de lever le readEither dans la fonction readEitherT, il l'élève à ErrorT String IO (Either String Int)
comme il se doit. Mais je devrais en quelque sorte l'obtenir à ErrorT String IO Int
.
Si je vais dans la mauvaise direction avec cela, quelle est la bonne façon de erreurs de poignée qui nécessitent IO (ou d'autres monades) et doivent être appelés à partir contexte monadique (voir la fonction foo
dans l'exemple
Editer: Apparemment, ce que j'essayais de faire n'était pas clair. Peut-être la fonction suivante décrit ce que et pourquoi je me demandais
maybePulseQuit :: Handle -> IO (Either String())
maybePulseQuit h = runErrorT $ do
f <- liftIO $ (communicate h "finished" :: IO (Either String Bool))
(ErrorT . pure) f >>= \b → liftIO $ when b $ liftIO pulseQuit
Cela fonctionne, mais est encore moche à cause des liaisons. C'est beaucoup plus clair que la version précédente qui avait un contrôle de cas. Est-ce la façon recommandée de le faire?
Je pensais par exemple faire try (foobar) dans ErrorT qui propagerait l'erreur possible dans la monade ErrorT. (IO (Either e a)) – Masse
J'ai ajouté un exemple de propagation d'erreur en utilisant 'ErrorT', peut-être que cela aidera – Yuras