代码之家  ›  专栏  ›  技术社区  ›  OllieB

修改transformer堆栈中的内部读取器

  •  6
  • OllieB  · 技术社区  · 8 年前

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

    问题

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

    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是外部单子,而我想在内部单子上使用它。

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

    1 回复  |  直到 8 年前
        1
  •  5
  •   K. A. Buhr    8 年前

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

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

    问题是,一般来说,对第二个论点唯一可能的操作是将其提升到 t (m (ReaderT r IO)) a 对于某些单声道变压器 t ,这不会给你买任何东西。

    也就是说 MonadTrans m 仅约束本身并不能提供足够的结构来做您想要做的事情。你要么需要 m 作为typeclass的实例,如 MFunctor mmorph 该软件包允许您通过提供以下功能以常规方式修改monad堆栈的内层:

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

    (胡安·巴勃罗·桑托斯就是这么说的),否则你需要一种能力来挖掘你的大脑结构 monad transformer将部分运行并重建它(这将是特定于transformer的)。

    hoist mmorph m 已经由变压器组成,由

    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 .

    第二种方法避免了 和必要的 MFunctor公司 实例,但需要根据您的具体情况进行裁剪 M . 对于上述类型,它看起来像:

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

    你基本上需要把单子运行到 ReaderT 然后将其重建,将层视为 StateT 小心。这正是 中的实例 mmorph