簡體   English   中英

修改變壓器堆棧中的內部讀取器

[英]Modifying inner reader in a transformer stack

我正在從許多不同的地方匯集代碼,我正在嘗試處理以下問題:

問題

我有一個變壓器堆棧,具有以下簡化類型:

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,而我想在內部使用它。

我也認為這可能與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 ,它不會給你任何東西。

也就是說, 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包支持的變換器組成,那么第一種方法(使用mmorph包中的hoist )將是最方便的。 例如,以下類型檢查,您不必編寫任何實例:

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一個。

第二種方法避免了hoist和必需的MFunctor實例,但需要針對您的特定M定制。 對於上面的類型,它看起來像:

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

你基本上需要將monad運行到ReaderT層然后重新StateT ,小心處理像StateT這樣的層。 這也正是什么MFunctor的情況下mmorph自動做。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM