Considérez l'exemple spécifique de IOT Maybe
. Comment écririez-vous une instance de Monad
pour cela? Vous pourriez commencer par quelque chose comme ceci :
instance Monad (IOT Maybe) where
return x = IOT (Just (return x))
IOT Nothing >>= _ = IOT Nothing
IOT (Just m) >>= k = IOT $ error "what now?"
where m' = liftM (runIOT . k) m
Vous avez maintenant m' :: IO (Maybe (IO b))
, mais vous avez besoin de quelque chose de type Maybe (IO b)
, où--le plus important--le choix entre Just
et Nothing
devrait être déterminé par m'
. Comment cela serait-il implémenté?
La réponse, bien sûr, est que cela ne serait pas fait, car cela ne peut pas l'être. Vous ne pouvez pas non plus justifier un unsafePerformIO
là-dedans, caché derrière une interface pure, car fondamentalement vous demandez une valeur pure--le choix du constructeur Maybe
--de dépendre du résultat de quelque chose dans IO
. Nnnnnope, cela n'arrivera pas.
La situation est encore pire dans le cas général, car un Monad
arbitraire (quantifié universellement) est encore plus impossible à défaire que IO
ne l'est.
À propos, le transformateur ST
que vous mentionnez est implémenté différemment de votre IOT
suggéré. Il utilise l'implémentation interne de ST
comme un monade de type State
utilisant des primitives spéciales fournies par le compilateur, et définit un transformateur de type StateT
basé sur cela. IO
est implémenté internalement de manière encore plus magique que ST
, et donc un hypothétique IOT
pourrait être défini de manière similaire.
Non que cela ne change vraiment quelque chose, à part peut-être vous donner un meilleur contrôle sur l'ordre relatif des effets secondaires impurs causés par IOT
.