进入包裹在变压器中的单子

Getting inside a monad wrapped in transformer

这是一个使用 Reader 转换器的人为示例:

{-# 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。可以做吗,还是我有"design issues"?

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,它是一个读取环境和returns 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 中)。可以用mapReaderTinspect更优雅

inspect :: ReaderT r Maybe a -> ReaderT r Maybe Bool
inspect = mapReaderT (return . isJust)