haskell - programacion - monadas javascript
¿Cuáles son las definiciones para>>=y return para la mónada IO? (3)
No hacen nada especial y solo están ahí para secuenciar acciones. Sería útil si piensas en ellos con diferentes nombres:
>> = se convierte en "y luego, utilizando el resultado de la acción anterior"
>> se convierte en "y luego"
el retorno se convierte en "no hacer nada, pero el resultado de no hacer nada es"
Esto convierte esta función en:
main :: IO ()
main = putStr "hello"
>> return " world"
>>= putStrLn
se convierte en:
main :: IO ()
main = putStr "hello" and then,
do nothing, but the result of doing nothing is " world"
and then, using the result of the previous action, putStrLn
Al final, no hay nada mágico sobre IO. Es exactamente tan mágico como un punto y coma en C.
Después de ver cómo se definen las mónadas List y Maybe, naturalmente comencé a sentir curiosidad acerca de cómo se definen las operaciones >>=
y return
para la mónada IO.
No hay implementación específica para IO
; es un tipo abstracto, con la implementación exacta no definida por el Informe Haskell. De hecho, no hay nada que detenga una implementación implementando IO
y su instancia de Monad
como primitivas del compilador, sin ninguna implementación de Haskell.
Básicamente, Monad
se usa como una interfaz para IO
, que no puede implementarse solo en Haskell puro. Probablemente esto sea todo lo que necesita saber en esta etapa, y profundizar en los detalles de la implementación probablemente solo confunda, en lugar de dar una idea.
Dicho esto, si observas el código fuente de GHC, verás que representa IO a
como una función que se parece a State# RealWorld -> (# State# RealWorld, a #)
(usando una tupla unboxed como el tipo de devolución), pero esto es engañoso; es un detalle de implementación, y estos valores State# RealWorld
no existen realmente en tiempo de ejecución. IO
no es una mónada de estado, 1 en teoría o en práctica.
En cambio, GHC usa primitivas impuras para implementar estas operaciones de IO; los "valores" State# RealWorld
son solo para detener las declaraciones de reordenamiento del compilador al introducir dependencias de datos de una declaración a la siguiente.
Pero si realmente quieres ver la implementación de return
de GHC y (>>=)
, aquí están:
returnIO :: a -> IO a
returnIO x = IO $ / s -> (# s, x #)
bindIO :: IO a -> (a -> IO b) -> IO b
bindIO (IO m) k = IO $ / s -> case m s of (# new_s, a #) -> unIO (k a) new_s
donde unIO
simplemente desenvuelve la función desde el interior del constructor de IO
.
Es importante observar que IO a
representa una descripción de un cálculo impuro que podría ejecutarse para producir un valor de tipo a
. El hecho de que exista una forma de obtener valores de la representación interna de IH de GHC no significa que esto se cumpla en general, o que pueda hacer algo así con todas las mónadas. Es puramente un detalle de implementación por parte de GHC.
1 La mónada de estado es una mónada utilizada para acceder y mutar un estado a través de una serie de cálculos; se representa como s -> (a, s)
(donde s
es el tipo de estado), que se ve muy similar al tipo que GHC usa para IO
, por lo tanto, la confusión.
Te decepcionará, pero >>=
en IO
mónada no es tan interesante. Para citar la fuente de GHC:
{- |
A value of type @''IO'' a@ is a computation which, when performed,
does some I//O before returning a value of type @a@.
There is really only one way to /"perform/" an I//O action: bind it to
@Main.main@ in your program. When your program is run, the I//O will
be performed. It isn''t possible to perform I//O from an arbitrary
function, unless that function is itself in the ''IO'' monad and called
at some point, directly or indirectly, from @Main.main@.
''IO'' is a monad, so ''IO'' actions can be combined using either the do-notation
or the ''>>'' and ''>>='' operations from the ''Monad'' class.
-}
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
Eso significa que la mónada IO
se declara como la instancia de mónada State
State
State#
y su . >>=
está definida allí (y su implementación es bastante fácil de adivinar)
Ver IO dentro del artículo en la wiki de Haskell para más detalles sobre la mónada IO
. También es útil consultar los documentos de Haskell , donde cada posición tiene un pequeño enlace de "Fuente" a la derecha.
Actualización: Y ahí va otra decepción, que es mi respuesta, porque no noté el ''#'' en State#
. Sin embargo, IO
comporta como una mónada de State
lleva el estado abstracto de RealWorld
Como @ehird escribió State#
es el compilador interno y >>=
para IO
GHC.Base se define en el módulo GHC.Base :
instance Monad IO where
{-# INLINE return #-}
{-# INLINE (>>) #-}
{-# INLINE (>>=) #-}
m >> k = m >>= / _ -> k
return = returnIO
(>>=) = bindIO
fail s = failIO s
returnIO :: a -> IO a
returnIO x = IO $ / s -> (# s, x #)
bindIO :: IO a -> (a -> IO b) -> IO b
bindIO (IO m) k = IO $ / s -> case m s of (# new_s, a #) -> unIO (k a) new_s