Reputation: 4421
This is a contrieved example using Reader Transformer:
{-# LANGUAGE UnicodeSyntax #-}
import Control.Monad.Reader
import Data.Char
conv ∷ Int → ReaderT Char Maybe String
conv n = do
yn ← ask
if yn == 'y'
then return $ chr n : " with Yes"
else lift Nothing
-- runReaderT (conv 98) 'y' Just "b with Yes"
-- runReaderT (conv 98) '@' Nothing
inspect ∷ ReaderT Char Maybe String → Bool
-- EDITED: as per suggestions, the correct type is monadic:
inspect ∷ ReaderT Char Maybe String → ReaderT Char Maybe Bool
inspect
is supposed to check whether the value inside is Nothing. Can it be done, or I am having "design issues"?
Upvotes: 1
Views: 88
Reputation: 24166
ReaderT
is exactly
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
-- a function that reads the environment^ |
-- and returns an m a^
For ReaderT r Maybe a
it's a function that reads the environment and returns a Maybe a
. You can make a function that reads the environment and checks if the result is Nothing
by composing this function with another function that checks whether the result is Nothing
. To check whether a Maybe a
is nothing, we can use isJust
, and to pack the resulting Bool
back into a Maybe Bool
we'd use return
.
inspect :: ReaderT r Maybe a -> ReaderT r Maybe Bool
inspect (ReaderT f) = ReaderT $ return . isJust . f
transformers provides a function, mapReaderT
that lets us manipulate the computation inside a ReaderT
mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b
mapReaderT f m = ReaderT $ f . runReaderT m
mapReaderT
just composes the function provided as its first argument with the function inside the ReaderT
(runReaderT
unwraps the function inside a ReaderT
). You can use mapReaderT
to write inspect
more elegantly.
inspect :: ReaderT r Maybe a -> ReaderT r Maybe Bool
inspect = mapReaderT (return . isJust)
Upvotes: 3