haskell - 修改变压器堆栈中的内部读取器

标签 haskell monad-transformers reader-monad

我正在从多个不同的地方收集代码,并尝试处理以下问题:

问题

我有一个具有以下简化类型的变压器堆栈:

action :: m (ReaderT r IO) a

并且我尝试在不同堆栈的上下文中使用该操作,该堆栈具有不同的阅读器环境:

desired :: m (ReaderT r' IO) a

我当然可以提供

f :: r' -> r

示例

things :: m (ReaderT r' IO) ()
things = do
   -- ... some stuff

   -- <want to use action here>
   action :: m (ReaderT r IO) a -- broken

    -- ... more stuff
   pure ()

我考虑过的

withReaderT :: (r' -> r) -> ReaderT r m a -> ReaderT r' m a

这有一个问题,即 ReaderT 是外部单子(monad),而我想在内部单子(monad)上使用它。

我也认为这可能与 MonadBase 或 MonadTransControl 有关,但我不熟悉它们的工作原理。

最佳答案

我认为不可能编写带有签名的函数:

changeReaderT :: (MonadTrans m)
                 => (r -> r') 
                 -> m (ReaderT r IO) a 
                 -> m (ReaderT r' IO) a

问题是,一般来说,第二个参数唯一可能的操作是将其提升为 t (m (ReaderT r IO)) a 对于某些 monad 转换器 t code>,它不会给你买任何东西。

也就是说,MonadTrans m 约束本身并不能提供足够的结构来完成您想要的操作。您需要将 m 作为 mmorph 包中的 MFunctor 等类型类的实例,以允许您修改 monad 堆栈的内层一般而言,通过提供如下函数:

hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b

(这就是 @Juan Pablo Santos 所说的),否则你需要有能力深入研究 m monad 转换器的结构来部分运行和重建它(这将是转换器 -具体)。

如果您的 m 已经由支持的转换器组成,则第一种方法(使用 mmorph 包中的 hoist)将是最方便的mmorph 包。例如,以下类型检查,您不必编写任何实例:

type M n = MaybeT (StateT String n)

action :: M (ReaderT Double IO) a
action = undefined

f :: Int -> Double
f = fromIntegral

desired :: M (ReaderT Int IO) a
desired = (hoist $ hoist $ withReaderT fromIntegral) action

M 中的每一层都需要一个提升机

第二种方法避免了 hoist 和必要的 MFunctor 实例,但需要根据您的特定 M 进行定制。对于上面的类型,它看起来像:

desired' :: M (ReaderT Int IO) a
desired' = MaybeT $ StateT $ \s ->
  (withReaderT fromIntegral . flip runStateT s . runMaybeT) action

您基本上需要将 monad 运行到 ReaderT 层,然后重新构建它,小心对待 StateT 等层。这正是 mmorph 中的 MFunctor 实例自动执行的操作。

关于haskell - 修改变压器堆栈中的内部读取器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46080752/

相关文章:

haskell - 试图了解单子(monad)变压器产生的类型

haskell - Reader monad - reader vs asks 功能区别?

haskell - 如何制作自定义过滤器?

haskell - 获取Data.Tree中节点的父级(haskell)

performance - Haskell Warp Performance vs Erlang Misultin 测试(如何加载文件内容一次并提供响应)

haskell - 用状态单子(monad)重构不纯递归?

haskell - mtl、transformers、monads-fd、monadLib 和选择悖论

list - Haskell:一个列表与另一个列表的子序列的叉积

haskell - 如何将 Reader Monad 与 (Int -> Int) 一起使用?

scala - Reader monad - 它如何符合 Monad 接口(interface)?