2015-08-21 2 views
3

Je souhaite lever une fonction comme mask_ :: IO a -> IO a pour créer une fonction avec cette signature: lmask_ :: StateT Bool IO a -> StateT IO a.Soulever une fonction avec un paramètre monad dans un transformateur monad

Mon problème est, comment gérer le callback/premier paramètre? Le code suivant ne serait-il pas incorrect puisqu'il exécuterait le rappel avant le code de mask_?

lmask_ :: StateT Bool IO a -> StateT Bool IO a 
lmask_ m = do 
    r <- m 
    lift (mask_ (return r)) 

Existe-t-il une façon générale de procéder? Un assistant comme lift1 :: MonadTrans t => (m a -> m a) -> (t m a -> t m a)?

Répondre

0

Si on généralise lmask_ pour se débarrasser de la StateT Bool IO, nous obtenons quelque chose comme ceci:

lift1 :: (Monad m, Monad (t m), MonadTrans t) => (m a -> m a) -> (t m a -> t m a) 
lift1 f term = do 
    x <- term 
    lift (f (return x)) 
2

En général, ce n'est pas possible sans savoir quelque chose sur le transformateur de monade. Cependant, il existe un moyen de le faire pour tous les transformateurs monad standard. Voir la classe de type MonadBaseControl. Sa superclasse MonadBase définit la monade inférieure dans une pile de transformateurs monad (IO pour toutes les piles incluant IO) et MonadBaseControl définit comment intégrer la monade dans la monade de base. Ses instances sont quelque peu alambiquées, mais une fois définies, il est possible de lever toutes ces fonctions comme mask_.

Dans votre cas, paquet base levé utilise la construction ci-dessus pour redéfinir les standards IO fonctions à MonadBaseControl levées. En particulier, il est mask_

mask_ :: MonadBaseControl IO m => m a -> m a 

qui peut être spécialisé à StateT Bool IO a -> StateT Bool IO a, comme StateT s a une instance de MonadBaseControl. Voir aussi Lift a function and its argument to a different monadic context.