Я не думаю, что можно написать функцию с подписью:
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
был экземпляром класса типов, такого как MFunctor
в пакете mmorph
, который позволяет вам изменять внутренний слой стека монад в общем виде, предоставляя такую функцию, как:
hoist :: Monad m => (forall a. m a -> n a) -> t m b -> t n b
(это то, что говорил @Juan Pablo Santos), иначе вам нужна возможность копаться в структуре вашего преобразователя монады m
, чтобы частично запустить и перестроить его (что будет зависеть от преобразователя).
Первый подход (с использованием hoist
из пакета mmorph
) будет наиболее удобным, если ваш m
уже состоит из трансформаторов, поддерживаемых пакетом 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
Вам понадобится hoist
для каждого слоя в M
.
Второй подход позволяет избежать hoist
и необходимых экземпляров MFunctor
, но требует адаптации к вашему конкретному M
. Для приведенного выше типа это выглядит примерно так:
desired' :: M (ReaderT Int IO) a
desired' = MaybeT $ StateT $ \s ->
(withReaderT fromIntegral . flip runStateT s . runMaybeT) action
По сути, вам нужно запустить монаду до уровня ReaderT
, а затем перестроить ее обратно, обращаясь с такими слоями, как StateT
, с осторожностью. Это именно то, что экземпляры MFunctor
в mmorph
делают автоматически.
person
K. A. Buhr
schedule
06.09.2017
ReaderT r m a -> ReaderT r' m a
,hoist
изMFunctor
сможет делать то, что вы хотите. - person Juan Pablo Santos   schedule 06.09.2017m
. Например, это невозможно сContT
. - person Li-yao Xia   schedule 06.09.2017MFunctor
для получения дополнительной информации. - person Juan Pablo Santos   schedule 07.09.2017