Multiple monads in one do-block

I'm currently trying to learn Haskell, and I really can't understand the concept of using only one monad in a do-block. If I have foo :: Int -> Maybe Int and you want to use, for example, the hIsEOF :: Handle -> IO Bool function in this function. Can someone please explain to me on some basic example how to use hIsEOF and somehow work with Bool ?

I try to search here and on google, but I always come across some advanced materials in which, as a rule, no one explains how they simply give tips on how to correctly insert the OP code. I have seen the monad transformers mentioned in these threads, but even after reading a few resources I cannot find the correct way to use them.

+8
haskell
source share
2 answers

The short answer is no. notation is based on two things

 return :: a -> ma >>= :: ma -> (a -> mb) -> mb 

Note >>= that although you can work with two different internal types ( a and b ), it only works with one external type, one monad ( m ). Both ma and a -> mb are the same monad.

The longer the answer, you have to convert them to one monad. For example, Maybe can be converted to IO as follows:

 maybeToIO Nothing = error "No thing" maybeToIO (Just a) = return a 

Monads, generally speaking, cannot be transformed into each other, although, with the exception of special cases.


So why >>= only works with one monad? Well, just look at this . It is defined to work with one monad at a time, and the definition-designation is defined for working with >>= . The reasons for choosing this definition are somewhat complicated, but I can edit it if someone wants to.

You can create your own >>= , which will work with several monads, and then use the repeating syntax , but this will probably be difficult.

+7
source share

When using monad transformers all you have to do is

  • change the function signature from Int -> Maybe Int to

     foo :: Int -> MaybeT IO Int 
  • remove all I / O actions inside the do block (or liftIO in this case). See here why you need this climb and what exactly it does .

  • run the function using runMaybeT

A minimal example might be:

 import Control.Monad.Trans (lift) import Control.Monad.Trans.Maybe (MaybeT, runMaybeT) import System.IO (openFile, hClose, hSeek, hIsEOF) import System.IO (IOMode(ReadMode), SeekMode(AbsoluteSeek)) foo :: Int -> MaybeT IO Int foo i = do h <- lift $ openFile "test.txt" ReadMode -- move the handle i bytes ahead lift . hSeek h AbsoluteSeek $ fromIntegral i eof <- lift $ hIsEOF h -- check if hit end of file lift $ hClose h if eof then fail "eof!" else return i 

then

 \> runMaybeT $ foo 1 Just 1 \> runMaybeT $ foo 100 -- would hit eof Nothing 

what you get from this will be of type:

 (runMaybeT . foo) :: Int -> IO (Maybe Int) 
+11
source share

All Articles