В еще более общем виде то, что вы пытаетесь сделать, это применить преобразование во внутренний слой стека трансформатора. Для двух произвольных монад, тип подписи может выглядеть следующим образом:
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 получается что-то очень похожее in the Monatron
package:
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
типов в основном одноранговые реализации fmap
вместо использования Functor
экземпляров непосредственно.
Кроме того, в течение двух Functor-подобных конструкторов типа F и G, функция с типом как (forall a. F a -> G a)
описывает a natural transformation от F до G. Там вполне возможно, другая реализация карты трансформатора, который вы хотите где-то в category-extras
пакете, но я «Не знаю, что такое теоретическая версия трансформатора монады, поэтому я не знаю, как это можно назвать.
Поскольку tmap
требует только Functor
экземпляра (который любой Monad
должен иметь) и естественное преобразование, и любая Monad
имеет естественное преобразование из Identity
монады, предоставленной return
, функция, которую вы хотите, может быть записана в общей для любого экземпляра FMonadT
as tmap (return . runIdentity)
- Исходная «основная» монада определяется как синоним трансформатора, примененный к Identity
, во всяком случае, как правило, с библиотеками трансформаторов.
Возвращаясь к вашему конкретному примеру, обратите внимание, что у Monatron действительно есть экземпляр FMonadT
для StateT
.
Я считаю, что редактировать TomMD является некорректным. Я считаю, что исходный 'g :: StateT [Int] IO Int' должен стоять. – glguy
Мне понравились другие изменения, исправлены скобки ... – HaskellElephant
Этот вопрос кажется тем, что я ищу, но ответы намного сложнее, чем http://stackoverflow.com/questions/17325485/combining-statet- io-with-state, который получил работу для меня. – crockeea