Ответ 1
В еще более общем виде то, что вы пытаетесь сделать, это применить преобразование к внутреннему слою стека трансформатора. Для двух произвольных монад подпись типа может выглядеть примерно так:
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
, это, вероятно, будет проще, но я могу представить, как определить класс другого типа для мест, в которых он работает. Я не думаю, что в типичных монадных трансформаторных библиотеках есть что-то подобное; однако некоторые просмотры взлома показывают что-то очень похожее в пакете 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
являются в основном ad-hoc реализациями fmap
вместо непосредственного использования экземпляров Functor
.
Кроме того, для двух конструкторов F-типа типа Functor функция с типом типа (forall a. F a -> G a)
описывает естественное преобразование из F для G. Возможно, существует еще одна реализация карты трансформатора, которую вы хотите где-то в пакете category-extras
, но я не уверен, что теоретическая версия трансформатора монады будет так, что я не знаю, что это может быть называется.
Так как tmap
требует только экземпляр Functor
(который должен иметь любой Monad
) и естественное преобразование, а любое Monad
имеет естественное преобразование из монады Identity
, предоставляемой return
, функция, которую вы хотите, может быть записана в общем случае для любого экземпляра FMonadT
как tmap (return . runIdentity)
- если предположить, что "базовая" монада определяется как синоним трансформатора, примененного к Identity
, во всяком случае, как правило, имеет место с трансформаторных библиотек.
Возвращаясь к вашему конкретному примеру, обратите внимание, что у Monatron действительно есть экземпляр FMonadT
для StateT
.