Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use ReaderT Maybe or MaybeT Reader?

I want to write a haskell program reading config and do something. The config is a Data.Map and will be injected into a Reader. And when we can't find a config item, the reading should be interrupted. Just stopped, no error messages are required. So I just want a Maybe monad(not Either monad).

The problem is, how should I stack the two monads, ReaderT Maybe or MaybeT Reader?

like image 484
kbridge4096 Avatar asked May 08 '17 05:05

kbridge4096


1 Answers

Finally I figure it out. Both of them are OK.

Assume every config item's value is just an Int.

The ReaderT ConfigMap Maybe Int will have a value like:

ReaderT (\r -> Just 123)

or

ReaderT (\r -> Nothing)

The MaybeT (Reader ConfigMap) Int will have a value like:

MaybeT (Reader (\r -> Just 123))

or:

MaybeT (Reader (\r -> Nothing))

With either, we can first do some read, then decide whether we should continue according whether the read returns a Nothing. The values have different outer shapes but the same functionality.

My little demo here:

import qualified Data.Map as M
import Control.Monad
import Control.Monad.Reader
import Control.Monad.Trans
import Control.Monad.Trans.Maybe

type Config = M.Map String Int

getConfig :: String -> MaybeT (Reader Config) Int
getConfig key = MaybeT $ do
  m <- ask
  return $ M.lookup key m

readAll :: Config -> Maybe (Int, Int)
readAll m =
  let r = runMaybeT $ do
      a <- getConfig "a"
      b <- getConfig "b"
      return (a, b)
  in runReader r m

main :: IO ()
main = do
  putStrLn $ show (readAll $ M.fromList [("x", 3), ("b", 4)])

My second demo:

import qualified Data.Map as M
import Control.Monad
import Control.Monad.Reader
import Control.Monad.Trans
import Control.Monad.Trans.Maybe

type Config = M.Map String Int

getConfig :: String -> ReaderT Config Maybe Int
getConfig key = ReaderT $ \r -> M.lookup key r

readAll :: Config -> Maybe (Int, Int)
readAll m =
  let r = runReaderT $ do
      a <- getConfig "a"
      b <- getConfig "b"
      return (a, b)
  in r m

main :: IO ()
main = do
  putStrLn $ show (readAll $ M.fromList [("a", 3), ("b", 4)])
like image 164
kbridge4096 Avatar answered Nov 22 '22 06:11

kbridge4096