В общем, вы пытаетесь применить преобразование к внутреннему слою стека трансформаторов.Для двух произвольных монад сигнатура типа может выглядеть примерно так:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 a) -> t m1 a -> t m2 a
В основном это более высокий уровень fmap
.На самом деле, возможно, было бы еще более целесообразно объединить его с картой для окончательного параметра:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 b) -> t m1 a -> t m2 b
Очевидно, что это не будет возможно во всех случаях, хотя, когда «источник»«монада Identity
, вероятно, будет проще, но я могу себе представить определение другого класса типов для мест, где он работает.Я не думаю, что есть что-то подобное в типичных библиотеках монадных преобразователей;однако, некоторые просмотры на hackage обнаруживают нечто очень похожее в пакете Monatron
:
class MonadT t => FMonadT t where
tmap' :: FunctorD m -> FunctorD n -> (a -> b)
-> (forall x. m x -> n x) -> t m a -> t n b
tmap :: (FMonadT t, Functor m, Functor n) => (forall b. m b -> n b)
-> t m a -> t n a
tmap = tmap' functor functor id
В сигнатуре для tmap'
типы FunctorD
в основном являютсяhoc реализации fmap
вместо непосредственного использования Functor
.
Кроме того, для двух конструкторов типа Functor F и G функция с типом, подобным (forall a. F a -> G a)
, описывает естественное преобразование от F до G. Возможно, есть еще одна реализация карты преобразователей, которую вы хотите где-то в пакете category-extras
, но я не уверен, какой будет теоретико-категоричная версия преобразователя монад, поэтому я не будузнать, как это может называться.
Поскольку tmap
требует только Functor
экземпляра (который должен иметь любой Monad
) и естественного преобразования, а любое Monad
имеет естественное преобразование из Identity
монаду, предоставляемую return
, необходимую функцию можно написать для любого экземпляра FMonadT
как tmap (return . runIdentity)
- при условии, что «базовая» монада определена как синоним fили преобразователь, применяемый к Identity
, во всяком случае, что обычно имеет место с библиотеками преобразователей.
Возвращаясь к вашему конкретному примеру, обратите внимание, что Monatron действительно имеет экземпляр FMonadT
для StateT
.