Supposons que j'ai une monade de l'Etat tels que:conjugueront avec des actions IO
data Registers = Reg {...}
data ST = ST {registers :: Registers,
memory :: Array Int Int}
newtype Op a = Op {runOp :: ST -> (ST, a)}
instance Monad Op where
return a = Op $ \st -> (st, a)
(>>=) stf f = Op $ \st -> let (st1, a1) = runOp stf st
(st2, a2) = runOp (f a1) st1
in (st2, a2)
avec des fonctions telles que
getState :: (ST -> a) -> Op a
getState g = Op (\st -> (st, g st)
updState :: (ST -> ST) -> Op()
updState g = Op (\st -> (g st,()))
et ainsi de suite. Je veux combiner diverses opérations dans cette monade avec des actions d'E/S. Je pourrais donc soit écrire une boucle d'évaluation dans lequel les opérations dans cette monade ont été effectuées et une action IO est exécutée avec le résultat, ou, je pense, je devrais être en mesure de faire quelque chose comme ce qui suit:
newtype Op a = Op {runOp :: ST -> IO (ST, a)}
Impression les fonctions auraient le type Op() et d'autres fonctions auraient le type Op a, par exemple, je pourrais lire un caractère du terminal en utilisant une fonction de type IO Char. Cependant, je ne suis pas sûr de savoir à quoi ressemblerait une telle fonction, puisque, par exemple, ce qui suit n'est pas valide.
runOp (do x <- getLine; setMem 10 ... (read x :: Int) ...) st
puisque getLine a le type IO Char, mais cette expression aurait le type Op Char. Dans les grandes lignes, comment ferais-je cela?
Je réalise (maintenant) que la solution présentée est standard, mais c'est une solution très intéressante (et élégante). Votre réécriture de mon code à l'aide d'un transformateur monad a été très utile, car elle a fourni un exemple concret. Merci! – danportin
Un bon complément éducatif à la solution pragmatique de Martijn. –