这是一个使用阅读器转换器的有用示例:
{-# 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
--编辑:根据建议,正确的类型是monadic:
inspect ∷ ReaderT Char Maybe String → ReaderT Char Maybe Bool
inspect
应该检查里面的值是否为Nothing。可以完成吗,或者我有"设计问题"?
ReaderT
正是
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
-- a function that reads the environment^ |
-- and returns an m a^
对于ReaderT r Maybe a
,它是一个读取环境并返回Maybe a
的函数。通过将此函数与另一个检查结果是否为Nothing
的函数组合,可以生成一个读取环境并检查结果是否是Nothing
的函数。为了检查Maybe a
是否为空,我们可以使用isJust
,并且为了将生成的Bool
打包回Maybe Bool
,我们将使用return
。
inspect :: ReaderT r Maybe a -> ReaderT r Maybe Bool
inspect (ReaderT f) = ReaderT $ return . isJust . f
transformers提供了一个函数mapReaderT
,它允许我们在ReaderT
中操作计算
mapReaderT :: (m a -> n b) -> ReaderT r m a -> ReaderT r n b
mapReaderT f m = ReaderT $ f . runReaderT m
mapReaderT
只是将作为其第一个自变量提供的函数与ReaderT
内部的函数组合(runReaderT
打开ReaderT
内部的函数)。您可以使用mapReaderT
来更优雅地编写inspect
。
inspect :: ReaderT r Maybe a -> ReaderT r Maybe Bool
inspect = mapReaderT (return . isJust)