Después de ver cómo se definen las mónadas List y Maybe, naturalmente sentí curiosidad acerca de cómo se definen las operaciones >>=
y return
para la mónada IO.¿Cuáles son las definiciones para >> = y return para la mónada IO?
Respuesta
No hay una 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 que implementa IO
y su instancia Monad
como primitivas del compilador, sin ninguna implementación de Haskell.
Básicamente, Monad
se utiliza como una interfaz -IO
, que solamente puede ser implementada en Haskell pura. 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 nos fijamos en el código fuente de GHC, encontrará que representa IO a
como una función que parece State# RealWorld -> (# State# RealWorld, a #)
(utilizando un unboxed tuple como el tipo de retorno), 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
es no una mónada de estado, en teoría o en la práctica.
En su lugar, GHC usa primitivas impuras para implementar estas operaciones de E/S; los "valores" State# RealWorld
son solo para detener las instrucciones de reordenamiento del compilador introduciendo dependencias de datos de una declaración a la siguiente.
Pero si realmente quieres ver la implementación de return
y (>>=)
de GHC, 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 IO
constructor.
Es importante señalar que IO a
representa una descripción de un cálculo impura que se podrían ejecutar para producir un valor de tipo a
. El hecho de que haya una manera de obtener valores de la representación interna de GHC de IO
no significa que esto se cumpla en general, o que pueda hacer tal cosa con todas las mónadas. Es puramente un detalle de implementación por parte de GHC.
El state monad 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 utiliza GHC para IO
, por lo tanto, la confusión.
Estará decepcionado, pero el >>=
en IO
mónada no es tan interesante. Para citar la fuente GHC:
{- |
A value of type @'IO' [email protected] is a computation which, when performed,
does some I\/O before returning a value of type @[email protected]
There is really only one way to \"perform\" an I\/O action: bind it to
@[email protected] 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 @[email protected]
'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 IO
mónada es declarada como la instancia de
State
State#
mónada,
y su
.>>=
se define allí (y su aplicación es bastante fácil de adivinar)
Ver IO inside artículo en Haskell wiki para obtener más detalles sobre IO
mónada. También es útil mirar Haskell docs, 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
se comporta como State
mónada llevar abstracta RealWorld
estado
Como @ehird escribió State#
es del compilador interno y >>=
para la IO
mónada se define en GHC.Base módulo:
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
+1 por mencionar el enlace de origen en Haskell docs – Sal
Esto no es cierto, sin embargo. Eso es 'State #' not 'State', y como se discutió en otra parte, la magia real que está sucediendo en la món IO no es capturada por sus operaciones en la ficha de estado. –
'GHC.IOBase' ha sido eliminado en [este compromiso] (http://git.haskell.org/packages/base.git/commit/00c0ee70fa4a8d14e583554584dc93704a69ba13). Las definiciones mencionadas ahora parecen estar en ['GHC.Base'] (http://hackage.haskell.org/package/base-4.7.0.2/docs/src/GHC-Base.html#bindIO). – jameshfisher
Ellos no hacen nada especial, y están ahí para secuenciar acciones. Sería de gran ayuda si usted piensa de ellos con diferentes nombres:
>> = se convierte en "y luego, usando el resultado de la acción anterior,"
>> convierte en "y luego,"
retorno se convierte en "no hacer nada, sino el resultado de no hacer nada es"
esto convierte a esta función:
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 en IO. Es exactamente tan mágico como un punto y coma en C.
Lo siento, pero he votado negativamente. Cuando algo * parece * mágico, simplemente decir que no es mágico no es suficiente: hay que apartar la cortina y mostrar cómo funcionó el truco de magia. –
No hay nada mágico sobre IO. Es exactamente tan mágico como un punto y coma en C. –
Pero eso no es del todo cierto. Los puntos y coma son un caso especial de la sintaxis básica de C. Los operadores '(>> =)' y '(>>)' y la función 'return' no tienen ese estado especial: ¡están definidos en una biblioteca! El hecho de que pueda, al menos a primera vista, definir un fragmento impuro del lenguaje como una biblioteca en un lenguaje que de otro modo sería masoquísticamente puro seguramente parece un poco misterioso si no sabe lo que está sucediendo. –
- 1. IO y quizás Interacción de mónada
- 2. ¿Cuáles son las implicaciones para redireccionar imágenes detrás de la etiqueta <image>?
- 3. ¿Cuáles son las bibliotecas comunes para C?
- 4. Haskell mónada: IO [doble] a [IO Doble]
- 5. ¿Cuáles son los 1> y 2> en la ventana de compilación de Visual Studio?
- 6. ¿Cuáles son las diferencias entre las definiciones de parámetros como (tipo y nombre) y (tipo * nombre)?
- 7. ¿Cuáles son algunas buenas y rápidas opciones de almacenamiento persistentes para los datos clave-> valor?
- 8. ¿Cuáles son las herramientas ágiles para PHP?
- 9. nhibernate: ¿cuáles son las mejores prácticas para implementar la igualdad?
- 10. ¿cuál es esta ecuación con la notación lambda "m >> n = m >> = \ _ -> n" en la declaración de mónada?
- 11. if-> return vs. if-> else efficiency
- 12. SQL Server return Filas que no son iguales <> a un valor y NULL
- 13. ¿Cuáles son las mejores soluciones livianas para arrastrar y soltar?
- 14. En C++, ¿cuáles son las diferencias entre static_cast <double> (a) y double (a)?
- 15. ¿Cuáles son las opciones para los efectos animados de jQuery?
- 16. ¿Cuáles son las mejores soluciones para gráficos y gráficos flash?
- 17. Haskell-problema: io cadena -> [int]
- 18. una función similar a (>> =) pero que devuelve una mónada diferente
- 19. return unknown Generic List <T>
- 20. ¿Cuál es la diferencia entre operator >> y operator >>> en java?
- 21. ¿Cuáles son las reglas para usar^para apuntar al valor?
- 22. ¿Cuáles son las razones para la subclasificación de NSArrayController?
- 23. incluyendo <xstring>, <cstring>, <string> y <wstring> en C++
- 24. ¿Cuáles son las diferentes técnicas para la memorización en Java?
- 25. ¿Cuáles son las clases posibles para la función OpenThemeData?
- 26. return Queryable <T> o List <T> en un Repository <T>
- 27. ¿Cuáles son las mejores prácticas para la lectura y escritura de datos intensivos en una HD?
- 28. Diferencia entre los operadores >>> y >>
- 29. Buenas estrategias para REST -> XML -> Datos principales -> UITableView?
- 30. ¿Cuáles son las razones de peso para usar un MemoryCache sobre una llanura de edad Dictionary <string, object>
+1 para la gran explicación de por qué State # se usa para preservar el orden de las declaraciones! – aelguindy
No estoy de acuerdo con que IO no sea una mónada de estado. Es solo que el estado que transportaba (comúnmente llamado 'RealWorld') es completamente abstracto. Este hecho no lo descalifica más como una verdadera Mónada de Estado que la naturaleza abstracta del 's'-thread en la' ST' Monad. –
@ JohnF.Miller: El modelo de mónada de estado de 'IO' puede modelar el cálculo secuencial (aunque' IO' no se implementa de esa manera en la práctica), pero no puede representar razonablemente la concurrencia. De todos modos, es definitivamente más confuso que útil, dado que ese modelo de 'IO' es * mucho * más restringido que una mónada de estado (o podrías hacer cosas como poner el estado del mundo de nuevo después de realizar algún lado -efectos, revirtiéndolos). – ehird