如何调用部分未嵌套的变压器?

How to call partially un-nest transformers?

给定嵌套的转换器 :: T2 of T1 of M0,我如何利用 :: T2 of M0:: M2

这是一个示例:我正在编写一些需要读取、记录和状态的函数。定义:

gameRoutine :: WriterT [String] (ReaderT Env (State Viable)) NUM

如果我想打电话给一些 stateFunction :: State Viable NUM

甚至stateWithReaderFunction :: ReaderT Env (State Viable) NUM,

我可以使用 lift:

gameRoutine = do
    x <- lift . lift $ stateFunction
    y <- lift $ stateWithReaderFunction

但是我怎么调用 writerFunction :: Writer [String] a 呢?

如何调用writerStateFunction :: WriterT [String] (State Viable) NUMgameRoutine定义的区别是缺少ReaderT层)?

显然我不想将他们的定义提升为 gameRoutine 之一。

嗯,基本上 mtl 的想法是您 不需要 那样做。您不是使用该特定签名定义 writerStateFunction,而是使用通用签名

定义它
writerStateFunction' :: (MonadWriter [String] m, MonadState Viable m)
          => m NUM

然后你尝试使用它的环境有一个额外的 Reader 层并不重要:这不会阻止 monad 同时拥有 MonadWriterMonadState 功能。

你可以一个Writer w a变成一个MonadWriter实例,比如:

import Control.Monad.Writer (MonadWriter, Writer, runWriter, tell)

lift' :: MonadWriter w m => Writer w a -> m a
lift' wr = do
    let (a, w) = runWriter wr
    tell w    -- manually re-log the log msg
    return a  -- wrap value into new context

那么,你可以简单地写:

gameRoutine :: WriterT [String] (ReaderT Env (State Viable)) NUM
gameRoutine = do
    a <- lift' writerFunction

只要writerFunction :: Writer [String] a可以特化为a ~ NUM