how to use IO Monad in another Monad - haskell

I use MongoDB library to handle data from Mongodb. There is a Monad called Action representing a DB read or write operation https://github.com/TonyGen/mongoDB-haskell/blob/master/doc/tutorial.md.
But, I find that when I in monad Action, I also want to do some IO which must be in an IO Monad. Some codes like
-- `Action' is a Monad
--
intoFile :: String -> Cursor -> Action IO ()
intoFile ric c = do
outH <- liftIO $ openFile ric AppendMode
liftIO $ hPutStrLn outH "Some log"
loopIntoFile outH c
liftIO $ hClose outH
There is a liftIO before any IO monad and I think it may be verbose. Any concise way to handle this ?

You can’t avoid the liftIO, unfortunately, because the standard IO actions are not overloaded to work in any MonadIO. But you can join sequences of IO actions under one call to liftIO:
intoFile :: String -> Cursor -> Action IO ()
intoFile ric c = do
outH <- liftIO $ do
openFile ric AppendMode
hPutStrLn outH "Some log"
loopIntoFile outH c
liftIO $ hClose outH
Or, if you intend to use the same IO operations repeatedly, you can introduce auxiliary definitions for them:
intoFile :: String -> Cursor -> Action IO ()
intoFile ric c = do
outH <- openLog ric AppendMode
log outH "Some log"
loopIntoFile outH c
closeLog outH
openLog path mode = liftIO (openFile path mode)
log handle message = liftIO (hPutStrLn handle message)
closeLog handle = liftIO (hClose handle)

You want to carry along 2 additional contexts - the IO context and Action context. That's the case for monad transformers, because they allow you to deal with layering monads and choose inside of do block which monad to choose for desired action. Here is a great explanation of why we need them and how to use them.

Related

Unwrap value from IO operation at a later time

Hello i was wondering how can you unwrap a value at a later time in the IO monad?
If a<-expression binds the result to a then can't i use (<-expression) as a parameter for a given method eg:
method (<-expression) where method method accepts the result of the evaluation?
Code
let inh=openFile "myfile" WriteMode
let outh=openFile "out.txt" WriteMode
hPutStrLn (<-outh) ((<-inh)>>=getLine)
I have not entered the Monad chapter just basic <- and do blocks but i suppose it has to do with monads.
Then if i want to pass the result if the evaluation to hGetLine can't i use something like:
(<-expression)=>>hGetLine
You already understand that <- operator kind of unwraps IO value, but it's actually the syntax of do notation and can be expressed like this (actually I'm not sure, which results you're trying to achieve, but the following example just reads the content from one file and puts the content to another file):
import System.IO
main = do
inh <- openFile "myfile" ReadMode
outh <- openFile "out.txt" WriteMode
inContent <- hGetLine inh
hPutStrLn outh inContent
hClose outh
According to documentation hGetLine, hPutStrlLn and hClose accept values of Handle type as an argument, but openFile returns IO Handle, so we need to unwrap it using <- operator
But if you want to use >>= function instead, then this is one of the options of doing it:
import System.IO
writeContentOfMyFile :: Handle -> IO ()
writeContentOfMyFile handler =
openFile "myfile" ReadMode >>= hGetLine >>= hPutStrLn handler
main =
withFile "out.txt" WriteMode writeContentOfMyFile

How to use an accumulator in a recursive IO action

I have the following problem:
I want to read from a file line by line and write the lines to another file. However, I want to return the number of lines.
Therefore, inside a pure function I would use an accumulator like this:
function parameters=method 0 ......
method accu {end case scenario} =accu
method accu {not end case} = accu+1 //and other stuff
How can I achieve the same in a do-block without using another function?
Concrete example
module Main where
import System.IO
import Data.Char(toUpper)
main::IO()
main=do
let inHandle=openFile "in.txt" ReadMode
let outHandle=openFile "out.txt" WriteMode
inHandle>>= \a ->outHandle>>= \b ->loop a b 0>>=print . show
loop::Handle->Handle->Int->IO Int
loop inh outh cnt=hIsEOF inh>>= \l ->if l then return elem
else
do
hGetLine inh>>=hPutStrLn outh
loop inh outh (cnt+1)
Edit
Refactored the way loop gets its parameters
P.S 2 (after K. A. Buhr's thorough response)
I. What I really wanted to achieve, was the last expression of the main method. I wanted to take the multiple IO Actions and bind their results to a method. Specifically:
inHandle>>= \a ->outHandle>>= \b ->loop a b 0>>=print . show
What I do not understand in this case is:
If inHandle>>= is supplied to \a -> and then the result is passed to ...>>=\b, do the variables inside the outer scope get closured in \b?
If not, shouldn't it be >>=\a->..>>= \a b? Shouldn't the inner scope hold a parameter corresponding to the result of the outer scope?
Eliminating the do inside the helper method
What I wanted to know, is if there is a way to glue together multiple actions without them being in a do block.
In my case:
loop::Handle->Handle->Int->IO Int
loop inh outh cnt=hIsEOF inh>>= \l ->if l then return elem
else
do
hGetLine inh>>=hPutStrLn outh
loop inh outh (cnt+1)
Can't I say something like:
if ... then ... elsehPutStrLn=<<action1 [something] v2=<<action2 [something] loop inh outh (cnt+1)
where something could be an operator? I do not know, that is why I am asking.
It looks like the answer to your last question still left you confused.
tl;dr: stop using >>= and =<< until you master the do-block notation which you can do by Googling "understanding haskell io" and working through lots of examples from tutorials.
Long answer...
First, I would suggest avoiding the >>= and =<< operators for now. Even though they are sometimes named "bind", they don't bind variables or bind parameters to methods or anything else like that, and they seem to be tripping you up. You may also find the section about IO from "A Gentle Introduction to Haskell" helpful as a quick introduction to how IO works.
Here's a very short explanation of IO that may help you, and it'll provide a basis for answering your question. Google for "understanding haskell io" to get a more in-depth explanation:
Super short IO explanation in three paragraphs:
(1) In Haskell, any value of type IO a is an IO action. An IO action is like a recipe that can be used (by executing the action) to perform some actual input/output and then produce a value of type a. So, a value of type IO String is an action that, if executed, will perform some input/output and produce a value of type String, while an IO () is an action that, if executed, will perform some input/output and produce a value of type (). In the latter case, because values of type () are useless, actions of type IO () are normally executed for their I/O side effects, such as printing a line of output.
(2) The only way to execute an IO action in a Haskell program is to give it the special name main. (The interactive interpreter GHCi provides more ways to execute IO actions, but let's ignore that.)
(3) IO actions can be combined using do-notation into a larger IO action. A do block consists of lines of the following form:
act -- action to be executed, with the result
-- thrown away (unless it's the last line)
x <- act -- action to be executed, with the result
-- named #x# for later lines
let y = expr -- add a name #y# for the value of #expr#
-- for later lines, but this has nothing to
-- do with executing actions
In the above templates, act can be any expression that evaluates to an IO action (i.e., a value of type IO a for some a). It's important to understand that the do-block does not itself execute any IO actions. Instead, it builds a new IO action that -- when executed -- will execute the given set of IO actions in the order they appear in the do-block, either throwing away or naming the values produced by executing these actions. The value produced by executing the whole do-block will be the value produced by the last line of the do-block (which has to be a line of the first form above).
A simple exmple
Therefore, if a Haskell program includes:
myAction :: IO ()
myAction = do
putStrLn "Your name?"
x <- getLine
let stars = "***"
putStrLn (stars ++ x ++ stars)
then this defines a value myAction of type IO (), an IO action. By itself, it does nothing, but if it is ever executed, then it will execute each of the IO actions (values of type IO a for various types a) in the do-block in the order they appear. The value produced by executing myAction will be the value produced by the last line (in this case, the value () of type ()).
Applied to the problem of copying lines
Armed with this explanation, let's tackle your question. First, how do we write a Haskell program to copy lines from one file to another using a loop, ignoring the problem of counting lines? Here's one way that's fairly similar to your code example:
import System.IO
myAction :: IO ()
myAction = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
loop inHandle outHandle
hClose outHandle
hClose inHandle
Here, if we check the type of one of these openFile calls in GHCi:
> :t openFile "in.txt" ReadMode
openFile "in.txt" ReadMode :: IO Handle
>
we see that it has type IO Handle. That is, this is an IO action that, when executed, performs some actual I/O (namely an operating system call to open a file) and then produces a value of type Handle, which is the Haskell value representing the open file handle. In your original version, when you wrote:
let inHandle = openFile "in.txt" ReadMode
all this did was assign a name inHandle to an IO action -- it didn't actually execute the IO action and so didn't actually open the file. In particular, the value of inHandle of type IO Handle was not itself a file handle, just an IO action (or "recipe") for producing a file handle.
In the version of myAction above, we've used the notation:
inHandle <- openFile "in.txt" ReadMode
to indicate that, if and when the IO action named by myAction is ever executed, it will start by executing the IO action openFile "in.txt" ReadMode" (that is, the value of that expression which has type IO Handle), and that execution will produce a Handle which will be named inHandle. Ditto for the next line to produce and name an open outHandle. We will then pass these open handles to loop in the expression loop inHandle outHandle.
Now, loop can be defined like so:
loop :: Handle -> Handle -> IO ()
loop inHandle outHandle = do
end <- hIsEOF inHandle
if end
then return ()
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle
It's worth taking a moment to explain this. loop is a fuction that takes two arguments, each Handle. When it's applied to two handles, as in the expression loop inHandle outHandle, the resulting value is of type IO (). That means it's an IO action, specifically, the IO action created by the outer do-block in the definition of loop. This do-block creates an IO action that -- when it is executed -- executes two IO actions in order, as given by the lines of the outer do-block. The first line is:
end <- hIsEOF inHandle
which takes the IO action hEof inHandle (a value of type IO Bool), executes it (which consists of asking the operating system if we've reached the end of file for the file represented by handle inHandle), and names the result end -- note that end will be a value of type Bool.
The second line of the do-block is the entire if statement. It produces a value of type IO (), so a second IO action. The IO action depends on the value of end. If end is true, the IO action will be the value of return () which, if executed, will perform no actual I/O and will produce a value () of type (). If end is false, the IO action will be the value of the inner do-block. This inner do-block is an IO action (a value of type IO ()) which, if executed, will execute three IO actions in order:
The IO action hGetLine inHandle, a value of type IO String that, when executed, will read a line from inHandle and produce the resulting String. As per the do-block, this result will be given the name line.
The IO action hPutStrLn outHandle line, a value of type IO () that, when exectued, will write line to outHandle.
The IO action loop inHandle outHandle, a recursive use of the IO action produced by the outer do-block, which -- when executed -- starts the whole process over again, starting with the EOF check.
If you put these two definitions (for myAction and loop) in a program, they won't do anything, because they're just definitions of IO actions. The only way to have them execute is to name one of them main, like so:
main :: IO ()
main = myAction
Of course, we could have just used the name main in place of myAction to get the same effect, as in the whole program:
import System.IO
main :: IO ()
main = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
loop inHandle outHandle
hClose inHandle
hClose outHandle
loop :: Handle -> Handle -> IO ()
loop inHandle outHandle = do
end <- hIsEOF inHandle
if end
then return ()
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle
Take some time to compare this to your "concrete example" above, and see where it's different and where it's simliar. In particular, can you figure out why I wrote:
end <- hIsEOF inHandle
if end
then ...
instead of:
if hIsEOF inHandle
then ...
Copying lines with a line count
To modify this program to count lines, a fairly standard way to do it would be to make the count a parameter to the loop function, and have loop produce the final value of the count. Since the expression loop inHandle outHandle is an IO action (above, it's of type IO ()), to have it produce a count we need to give it type IO Int, as you've done in your example. It will still be an IO action but now -- when it is executed -- it'll produce a useful Int value instead of a useless () value.
To make this change, main will have to invoke loop with a starting counter, name the value it produces, and output that value to the user.
To make it absolutely clear: main's value is still an IO action created by a do-block. We're just modifying one of the lines of the do-block. It used to be:
loop inHandle outHandle
which evaluated to a value of type IO () representing an IO action that -- when the whole do-block was executed -- would be executed when its turn came to copy the lines from one file to the other before producing a () value to be thrown away. Now, it's going to be:
count <- loop inHandle outHandle 0
where the right-hand side will evaluate to a value of type IO Int representing an IO action that -- when the whole do-block is executed -- will be executed when its turn comes to copy the lines from one file to the other before producing a count value of type Int to be named count for later do-block steps.
Anyway, the modified main looks like this:
main :: IO ()
main = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
count <- loop inHandle outHandle 0
hClose inHandle
hClose outHandle
putStrLn (show count) -- could just write #print count#
Now, we rewrite loop to maintain a count (taking the running count as a parameter through recursive calls and producing the final value when the IO action is executed):
loop :: Handle -> Handle -> Int -> IO Int
loop inHandle outHandle count = do
end <- hIsEOF inHandle
if end
then return count
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle (count + 1)
The whole program is:
import System.IO
main :: IO ()
main = do
inHandle <- openFile "in.txt" ReadMode
outHandle <- openFile "out.txt" WriteMode
count <- loop inHandle outHandle 0
hClose inHandle
hClose outHandle
putStrLn (show count) -- could just write #print count#
loop :: Handle -> Handle -> Int -> IO Int
loop inHandle outHandle count = do
end <- hIsEOF inHandle
if end
then return count
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle (count + 1)
The rest of your question
Now, you asked about how to use an accumulator within a do-block without using another function. I don't know if you meant without using another function besides loop (in which case the answer above satisfies the requirement) or if you meant without using any explicit loop at all.
If the latter, there are a couple of approaches. First, there are monadic loop combinators available in the monad-loops package that can allow you to do the following (to copy without counting). I've also switched to using withFile in place of explicit open/close calls:
import Control.Monad.Loops
import System.IO
main :: IO ()
main =
withFile "in.txt" ReadMode $ \inHandle ->
withFile "out.txt" WriteMode $ \outHandle ->
whileM_ (not <$> hIsEOF inHandle) $ do
line <- hGetLine inHandle
hPutStrLn outHandle line
and you can count lines with a state monad:
import Control.Monad.State
import Control.Monad.Loops
import System.IO
main :: IO ()
main = do
n <- withFile "in.txt" ReadMode $ \inHandle ->
withFile "out.txt" WriteMode $ \outHandle ->
flip execStateT 0 $
whileM_ (not <$> liftIO (hIsEOF inHandle)) $ do
line <- liftIO (hGetLine inHandle)
liftIO (hPutStrLn outHandle line)
modify succ
print n
With respect to removing the last do block from the definition of loop above, there's no good reason to do this. It's not like do blocks have overhead or introduce some extra processing pipeline or something. They're just ways of constructing IO action values. So, you could replace:
else do
line <- hGetLine inHandle
hPutStrLn outHandle line
loop inHandle outHandle (count + 1)
with
else hGetLine inHandle >>= hPutStrLn outHandle >> loop inHandle outHandle (count + 1)
but this is a purely syntactic change. The two are otherwise identical (and will almost certainly compile to equivalent code).

What's an idiomatic way of handling a lazy input channel in Haskell

I am implementing an IRC bot and since I am connecting over SSL by using OpenSSL.Session I use lazyRead function to read data from the socket. During the initial phase of the connection I need to perform several things in order: nick negotiation, nickserv identification, joining channels etc) so there is some state involved. Right now I came up with the following:
data ConnectionState = Initial | NickIdentification | Connected
listen :: SSL.SSL -> IO ()
listen ssl = do
lines <- BL.lines `fmap` SSL.lazyRead ssl
evalStateT (mapM_ (processLine ssl) lines) Initial
processLine :: SSL.SSL -> BL.ByteString -> StateT ConnectionState IO ()
processLine ssl line = do case message of
Just a -> processMessage ssl a
Nothing -> return ()
where message = IRC.decode $ BL.toStrict line
processMessage :: SSL.SSL -> IRC.Message -> StateT ConnectionState IO ()
processMessage ssl m = do
state <- S.get
case state of
Initial -> when (IRC.msg_command m == "376") $ do
liftIO $ putStrLn "connected!"
liftIO $ privmsg ssl "NickServ" ("identify " ++ nick_password)
S.put NickIdentification
NickIdentification -> do
when (identified m) $ do
liftIO $ putStrLn "identified!"
liftIO $ joinChannel ssl chan
S.put Connected
Connected -> return ()
liftIO $ print m
when (IRC.msg_command m == "PING") $ (liftIO . pong . mconcat . map show) (IRC.msg_params m)
So when I get to the "Connected" state I still end up going through the case statement even though it's only really needed to initialize the connection. The other problem is that adding nested StateT's would be very painful.
Other way would be to replace mapM with something custom to only process lines until we are connected and then start another loop over the rest. This would require either keeping track of what's left in the list or invoking SSL.lazyRead once again (which is not too bad).
Another solution is to keep the remaining lines list in the state and draw lines when needed similar to getLine.
What's the better thing to do in this case? Would Haskell's laziness make it so that we go directly to Connected case after state stops updating or is case always strict?
You can use the Pipe type from pipes. The trick is that instead of creating a state machine and a transition function you can encode the the state implicitly in the control flow of the Pipe.
Here is what the Pipe would look like:
stateful :: Pipe ByteString ByteString IO r
stateful = do
msg <- await
if (IRC.msg_command msg == "376")
then do
liftIO $ putStrLn "connected!"
liftIO $ privmsg ssl "NickServ" ("identify " ++ nick_password)
yield msg
nick
else stateful
nick :: Pipe ByteString ByteString IO r
nick = do
msg <- await
if identified msg
then do
liftIO $ putStrLn "identified!"
liftIO $ joinChannel ssl chan
yield msg
cat -- Forward the remaining input to output indefinitely
else nick
The stateful pipe corresponds to the stateful part of your processMessage function. It handles initialization and authentication, but defers further message processing to downstream stages by re-yielding the msg.
You can then loop over every message this Pipe yields by using for:
processMessage :: Consumer ByteString IO r
processMessage = for stateful $ \msg -> do
liftIO $ print m
when (IRC.msg_command m == "PING") $ (liftIO . pong . mconcat . map show) (IRC.msg_params m)
Now all you need is a source of ByteString lines to feed to processMessage. You can use the following Producer:
lines :: Producer ByteString IO ()
lines = do
bs <- liftIO (ByteString.getLine)
if ByteString.null bs
then return ()
else do
yield bs
lines
Then you can connect lines to processMessage and run them:
runEffect (lines >-> processMessage) :: IO ()
Note that the lines Producer does not use lazy IO. It will work even if you use the strict ByteString module, but the behavior of the entire program will still be lazy.
If you want to learn more about how pipes works, you can read the pipes tutorial.

Composing IO Monads using do

I have code in the Reader Monad, so as to pass a file handle as an invisible parameter down the Reader chain.
In writeMail, I am trying to create a Reader, which, when run using runReader, produces an IO () output which is itself the result of a chain of IO monads
writeMail :: Reader Handle (IO ())
writeMail mail = do
wmh <- writeMailHeaders mail
wmb <- writeMailBody mail
return $ wmh >>= \_ -> wmb
However I am finding that only the last in the IO chain i.e. wmb, prints at the console.
Can anyone see what I should be doing to get wmh, then wmb to print?
With simpler example:
module Read where
import Data.Functor.Identity
write :: Monad m => m (IO ())
write = do
a <- return $ putStrLn "foo"
b <- return $ putStrLn "bar"
return $ a >> b
main :: IO ()
main = runIdentity write
main prints both "foo" and "bar". So I suspect the error is in writeMailHeaders.
What you need is not just a reader, but a ReaderT monad transformer with IO as a base monad.
Since your example was incomplete, I made some changes to show your options:
import Control.Monad.Reader
writeMail :: ReaderT Handle IO ()
writeMail = do
-- Here's how you get your handle to further do something to it:
handle <- ask
-- Here's how you do the IO actions.
-- Notice the `lift` function,
-- which allows us to run actions of the base monad,
-- which in that case is `IO`.
lift $ do
print "bla bla"
print "bla"

How do I break out of a loop in Haskell?

The current version of the Pipes tutorial, uses the following two functions in one of the example:
stdout :: () -> Consumer String IO r
stdout () = forever $ do
str <- request ()
lift $ putStrLn str
stdin :: () -> Producer String IO ()
stdin () = loop
where
loop = do
eof <- lift $ IO.hIsEOF IO.stdin
unless eof $ do
str <- lift getLine
respond str
loop
As is mentinoed in the tutorial itself, P.stdin is a bit more complicated due to the need to check for the end of input.
Are there any nice ways to rewrite P.stdin to not need a manual tail recursive loop and use higher order control flow combinators like P.stdout does? In an imperative language I would use a structured while loop or a break statement to do the same thing:
while(not IO.isEOF(IO.stdin) ){
str <- getLine()
respond(str)
}
forever(){
if(IO.isEOF(IO.stdin) ){ break }
str <- getLine()
respond(str)
}
I prefer the following:
import Control.Monad
import Control.Monad.Trans.Either
loop :: (Monad m) => EitherT e m a -> m e
loop = liftM (either id id) . runEitherT . forever
-- I'd prefer 'break', but that's in the Prelude
quit :: (Monad m) => e -> EitherT e m r
quit = left
You use it like this:
import Pipes
import qualified System.IO as IO
stdin :: () -> Producer String IO ()
stdin () = loop $ do
eof <- lift $ lift $ IO.hIsEOF IO.stdin
if eof
then quit ()
else do
str <- lift $ lift getLine
lift $ respond str
See this blog post where I explain this technique.
The only reason I don't use that in the tutorial is that I consider it less beginner-friendly.
Looks like a job for whileM_:
stdin () = whileM_ (lift . fmap not $ IO.hIsEOF IO.stdin) (lift getLine >>= respond)
or, using do-notation similarly to the original example:
stdin () =
whileM_ (lift . fmap not $ IO.hIsEOF IO.stdin) $ do
str <- lift getLine
respond str
The monad-loops package offers also whileM which returns a list of intermediate results instead of ignoring the results of the repeated action, and other useful combinators.
Since there is no implicit flow there is no such thing like "break". Moreover your sample already is small block which will be used in more complicated code.
If you want to stop "producing strings" it should be supported by your abstraction. I.e. some "managment" of "pipes" using special monad in Consumer and/or other monads that related with this one.
You can simply import System.Exit, and use exitWith ExitSuccess
Eg. if (input == 'q')
then exitWith ExitSuccess
else print 5 (anything)

Resources