punund
punund

Reputation: 4421

Getting inside a monad wrapped in transformer

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

Answers (1)

Cirdec
Cirdec

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

Related Questions