Bind the monadic value (m2 a) inside some other monad m1

Working in Dojo encoding today I tried the following

example :: IO () example = do input <- getLine parsed <- parseOnly parser input ... 

where parseOnly :: Parser a -> Either String a (from attoparsec ), of course, the compiler complained that Either .. not IO .. essentially tells me that I am mixing monads.

Of course, this can be solved with

  case parseOnly parser input of .. -> .. 

which, it seems to me, is ridiculous. I also assume that someone else had this problem before, and the solution, I think, is connected with monad transformers, but I can’t put the last bits together.

It also reminded me of liftIO , but in another way I think it solves the problem of raising the action of the EUT that occurs inside some surrounding monad (more precisely, MonadIO - for example, inside Snap , when one wants to print something before stdout , getting some http )

A more general problem arises for Monad m1 and (other) Monad m2 , how can I do something like

 example = do a <- m1Action b <- m2Action .. 
+1
haskell monads monad-transformers
source share
3 answers

You cannot, in general. The entire do block must be one specific monad (because example must have a specific type). If you could link an arbitrary other monad inside the do block, you would have unsafePerformIO .

Monad transformers allow you to create one monad, combining various things that other monads can do. But you must decide that all actions in your do block use the same monad transformer stack to use them, they are not a way to arbitrarily switch monads mid do-block.

Your case solution only works because you have a certain known monad (Either) that has a way to extract values ​​from the inside. These are not all monads, therefore it is impossible to build a common solution without knowing the specific monads involved. This is why the do block syntax does not provide such a shortcut.

+5
source share

In general, monad transformers are designed for this kind of interleaving. You can use ExceptT

 example :: IO (Either String ()) example = runExceptT $ do input <- liftIO getLine parsed <- parseOnly parser input ... 

Note that parseOnly should return an ExceptT String IO a for some a . Or better is ExceptT String ma for any m . Or, if you want to return parseOnly Either String a , this is

 example :: IO (Either String ()) example = runExceptT $ do input <- lift getLine parsed <- ExceptT $ return $ parseOnly parser input ... 

But I think that all you need is just

 eitherToIO :: Either String a -> IO a eitherToIO (Left s) = error s eitherToIO (Right x) = return x parseOnly :: ... -> String -> Either String Int example :: IO () example = do input <- getLine parsed <- eitherToIO $ parseOnly parser input ... 
+3
source share

You need to do an expression type check; as in pure code. Here,

 ... = do a <- act1 -- m1 monad b <- act2 -- m2 monad ... 

de-sugars to:

 ... = act1 >>= (\a -> act2 >>= \b -> ...) 

>>= has a signature:

 (>>=) :: Monad m => ma -> (a -> mb) -> mb 

external linking is specialized with m1 , so it expects the expression inside the bracket to be of type: a -> m1 b , while internal linking is specialized for m2 , so the expression inside the brackets will be of type a -> m2 b :

 -- outer bind expects ( \a -> m1 b ) act1 >>= (\a -> act2 >>= \b -> ...) -- inner bind results ( \a -> m2 b ) 

for this, to check the type, you need the signature function m2 b -> m1 b between them; this is lift for a particular class of m2 and m1 monads: namely m1 ~ t m2 where t is an instance of MonadTrans :

 lift :: (Monad m, MonadTrans t) => ma -> tma 
+2
source share

All Articles