De façon plus générale, vous essayez d'appliquer une transformation à une couche interne d'une pile de transformateurs. Pour deux monades arbitraires, la signature de type pourrait ressembler à ceci:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 a) -> t m1 a -> t m2 a
Fondamentalement, un niveau supérieur fmap
. En fait, il serait probablement encore plus logique de le combiner avec une carte sur le dernier paramètre ainsi:
fmapMT :: (MonadTrans t, Monad m1, Monad m2) => (m1 a -> m2 b) -> t m1 a -> t m2 b
Il est clair que cela ne va pas être possible dans tous les cas, bien que lorsque la « source » monade c'est Identity
c'est plus facile, mais je peux imaginer définir une autre classe de type pour les endroits où ça marche. Je ne pense pas qu'il y ait quelque chose comme ça dans les bibliothèques de transformateurs monad typiques; Cependant, un peu de navigation sur hackage se présente quelque chose de très similaire 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
Dans la signature tmap'
, les FunctorD
types sont essentiellement mises en œuvre ad hoc de fmap
au lieu d'utiliser Functor
instances directement.
En outre, deux constructeurs de type semblables Functor F et G, une fonction avec un type comme (forall a. F a -> G a)
décrit a natural transformation de F à G. Il est tout à fait peut-être une autre mise en oeuvre du plan de transformation que vous voulez quelque part dans le paquet category-extras
mais je Je ne suis pas sûr de ce que serait la version théorique d'un transformateur de monade, donc je ne sais pas comment on pourrait l'appeler.
Depuis tmap
ne nécessite qu'une instance Functor
(que tout Monad
doit avoir) et une transformation naturelle et toute Monad
a une transformation naturelle de la Identity
monade fournies par return
, la fonction que vous voulez peut être écrit de manière générique pour toute instance de - l'utilisation de la monade "de base" est définie comme un synonyme du transformateur appliqué à Identity
, dans tous les cas, ce qui est généralement le cas avec les bibliothèques de transformateurs.
En revenant à votre exemple spécifique, notez que Monatron a effectivement une instance de FMonadT
pour StateT
.
Je crois que la modification de TomMD est incorrect. Je crois que l'original 'g :: StateT [Int] IO Int' devrait rester. – glguy
J'ai aimé les autres changements, fixé la parenthèse ... – HaskellElephant
Cette question semble être ce que je cherche, mais les réponses sont beaucoup plus compliquées que http://stackoverflow.com/questions/17325485/combining-statet- io-avec-état, qui a fait le travail pour moi. – crockeea