2010-05-11 13 views
9

No entiendo el álgebra exacta y la teoría detrás de las mónadas de Haskell. Sin embargo, cuando pienso en la programación funcional en general, tengo la impresión de que el estado se modelaría tomando un estado inicial y generando una copia para representar el siguiente estado. Esto es como cuando una lista se agrega a otra; ninguna de las listas se modifica, pero se crea y devuelve una tercera lista.¿Se puede pensar que las mónadas de Can Haskell usan y devuelven un parámetro de estado oculto?

¿Es por lo tanto válido pensar en operaciones monádicas como tomar implícitamente un objeto de estado inicial como parámetro y devolver implícitamente un objeto de estado final? Estos objetos de estado se ocultarían para que el programador no tenga que preocuparse por ellos y controlar cómo se accede a ellos. Entonces, el programador no intentará copiar el objeto que representa la secuencia IO como lo fue hace diez minutos.

En otras palabras, si tenemos este código:

main = do 
    putStrLn "Enter your name:" 
    name <- getLine 
    putStrLn ("Hello " ++ name) 

... ¿Está bien pensar en la mónada IO y el "hacer" la sintaxis como la representación de este tipo de código?

putStrLn :: IOState -> String -> IOState 
getLine :: IOState -> (IOState, String) 
main :: IOState -> IOState 

-- main returns an IOState we can call "state3" 
main state0 = putStrLn state2 ("Hello " ++ name) 
    where (state2, name) = getLine state1 
     state1 = putStrLn state0 "Enter your name:" 

Respuesta

18

No, eso no es lo que hacen las mónadas en general. Sin embargo, su analogía es de hecho exactamente correcta con respecto al tipo de datos State s a, que resulta ser una mónada. State se define así:

newtype State s a = State { runState :: s -> (a, s) } 

...donde la variable tipo s es el valor de estado y a es el valor "normal" que se utiliza. Entonces, un valor en "la mónada de estado" es solo una función desde un estado inicial, hasta un valor de retorno y un estado final. El estilo monádico, como se aplica a State, no hace más que enhebrar automáticamente un valor de estado a través de una secuencia de funciones.

El ST mónada es superficialmente similar, pero utiliza la magia para permitir cálculos con verdadera efectos secundarios, pero sólo de tal manera que los efectos secundarios no puede ser observado desde el exterior usos particulares de ST.

El IO mónada es esencialmente una mónada ST establecido en "más mágica", con efectos secundarios que tocan el mundo exterior y sólo un único punto en el que se ejecutan los cálculos IO, es decir, el punto de entrada para todo el programa. Sin embargo, en algún nivel conceptual, todavía se puede pensar en él como enhebrar un valor "Estado" a través de las funciones de la manera regular State hace.

Sin embargo, otras mónadas no tienen necesariamente nada que ver con el estado del enhebrado o las funciones de secuenciación, o lo que sea. Las operaciones necesarias para que algo sea una mónada son increíblemente general y abstracta. Por ejemplo, usar Maybe o Either como mónadas le permite usar funciones que pueden devolver errores, con el manejo de estilo monádico escapándose del cálculo cuando ocurre un error de la misma manera que State enhebra un valor de estado. El uso de listas como una mónada le da no determinismo, que le permite aplicar simultáneamente las funciones de múltiples entradas y ver todas las salidas posibles, con el estilo monádico la aplicación automática de la función de cada argumento y recoger todas las salidas.

+0

Ah sí, me olvidé de las Mónadas Maybe y Oither. – AJM

+0

@AJM It * es * una forma válida de pensar en IO. Puedes imaginar que IO es una Mónada de estado con toda la realidad como 's'. – PyRulez

4

No mónadas en general, pero para la mónada IO, sí - de hecho, el tipo IO a se define a menudo como el tipo de función RealWorld -> (RealWorld, a). Entonces, en esta vista, el tipo desajustado de putStrLn es String -> RealWorld -> (RealWorld,()) y getChar es RealWorld -> (RealWorld, Char) - y solo lo aplicamos parcialmente, con el enlace monádico teniendo la precaución de evaluarlo completamente y pasar el RealWorld. (La biblioteca ST de GHC incluye realmente un tipo RealWorld muy real, aunque se describe como "profundamente mágico" y no para el uso real.)

Sin embargo, hay muchas otras mónadas que no tienen esta propiedad. No se pasa el RealWorld con, por ejemplo, las mónadas [1,2,3,4] o Just "Hello".

+0

La verdadera razón por la que dicen 'RealWorld' no es para uso real es que no quieren que la gente haga algo como' setPresident RealWorld "pyrulez" 'o algo así (quieren todo el poder para ellos). – PyRulez

8

¿Es por lo tanto válido pensar que las operaciones monádicas toman implícitamente un objeto de estado inicial como parámetro y devuelven implícitamente un objeto de estado final?

Esto parece ser un punto de fricción común para las mónadas de aprendizaje, es decir, tratando de encontrar la manera de una sola mónada mágica sopa primordial es a la vez útil para representar los cómputos con estado, los cálculos que pueden fallar, los cálculos no deterministas, excepciones , continuaciones, secuenciación de efectos secundarios, etc.

El estado de subprocesamiento a través de una secuencia de cálculos con estado es un solo ejemplo de una operación que cumple con las leyes de mónada.

Tiene razón al observar que las mónadas State y IO son primos cercanos, pero su analogía se derrumbará si intenta insertar, por ejemplo, la lista de mónadas.

0

Prefiero pensar en las mónadas como objetos que representan acciones retardadas (runXXX, principal) con resultados que se pueden combinar según ese resultado.

return "somthing" 
actionA >>= \x -> makeActionB x 

Y esa acción no es necesaria para completar el estado. Es decir. usted puede pensar en una mónada de construcción de funciones como esta:

instance Monad ((->) a) where 
    m >>= fm = \x -> fm (m x) x 
    return = const 

sqr = \x -> x*x 
cube = \x -> x*x*x 

weird = do 
    a <- sqr 
    b <- cube 
    return (a+b) 
3

Absolutamente no. Esto no es lo que las mónadas son en general. Puede usar mónadas para pasar datos implícitamente, pero esa es solo una aplicación. Si usas este modelo de mónadas, te perderás muchas de las cosas realmente geniales que las mónadas pueden hacer.

En su lugar, piense en las mónadas como piezas de datos que representan un cálculo. Por ejemplo, hay un sentido en el que pasar implícitamente datos no es puro porque los lenguajes puros insisten en que sea explícito sobre todos sus argumentos y tipos de devolución. Por lo tanto, si desea pasar información implícitamente, puede hacer esto: definir un nuevo tipo de datos que sea representación de hacer algo impuro y luego escribir un fragmento de código para trabajar con eso.

Un ejemplo extremo (solo un ejemplo teórico, es poco probable que desee hacer esto) sería este: C permite cálculos impuros, por lo que podría definir un tipo que represente un fragmento de código C. Luego puede escribir un intérprete que tome una de estas estructuras C y la interprete. Todas las mónadas son así, aunque generalmente mucho más simples que un intérprete C. Pero esta vista es más poderosa porque también explica las mónadas que no se tratan de pasar por un estado oculto.

Probablemente también deberías tratar de resistir la tentación de ver a IO como pasando por un estado mundial oculto. La implementación interna de IO no tiene nada que ver con la forma en que debe pensar en IO. La mónada IO se trata de construir representaciones de las E/S que desea realizar. Usted devuelve una de estas representaciones al sistema de tiempo de ejecución Haskell y depende de ese sistema implementar su representación como lo desee.

Cada vez que quiere hacer algo, y no se puede ver la forma de implementar directamente de una manera pura, pero se puede ver cómo construir una estructura de datos pura a describen quieren lo desea, puede tener una aplicación para una mónada, especialmente si su estructura es naturalmente un árbol de algún tipo.

Cuestiones relacionadas