How to use monad in this case?

Question

Say, I want to connect to a database and do some query. I decide to use monad to implement like this:

queryDatabase :: IO String
...

doSomeQuery :: IO ()
doSomeQuery = do
    conn   <- connectToDatabase
    result <- queryDatabase conn
    return ()

doQueryForever :: IO ()
doQueryForever = forever doSomeQuery

But, I do not want have a new connection to database every time, I want to reuse the old connection and reconnect when the old connection broken. So, I redesign my program like this:

queryDatabase :: IO (Either Connection String)
-- when the connection is broken, return (Left oldConnection)

doSomeQuery :: IO ()
doSomeQuery = do
    conn   <- connectToDatabase
    result <- queryDatabase conn
    return ()

doQueryForever :: IO ()
doQueryForever = do
    conn   <- connectToDatabase  -- Firstly, create a connection

    forever $ do
        result <- queryDatabase conn -- How can I update this conn when broken?
        case result of
          --
          -- Here is the QUESTION. 
          -- If I create a New connection, it seems difficult for me to 
          -- make the new connection use by queryDatabase function.
          --
          Left oldConn -> createNewConnection
          Right s -> putStrLn s

The Question is: How can I make the new connection just created to be used by queryDatabase function ? When forever function run again, I think the conn it uses is the old connection.


Show source
| haskell   | monads   2016-12-10 10:12 1 Answers

Answers ( 1 )

  1. 2016-12-10 15:12

    doQueryForever should take a connection as an argument. When a query fails, call it recursively with a new connection; when a query succeeds, call it recursively with the existing connection. The initial call, of course, also needs to take the first connection.

    handleResult result = ...
    runQueries = connectToDatabase >>= doQueryForever
    
    doQueryForever conn = do
        result <- queryDatabase conn
        case result of
            Left _ -> runQueries
            Right s -> handleResult s >> doQueryForever conn
    
    runQueries
    
◀ Go back