2012-05-04 21 views
17

Sé que esScala equivalente de do-notación de Haskell (una vez más)

do 
    x <- [1, 2, 3] 
    y <- [7, 8, 9] 
    let z = (x + y) 
    return z 

puede expresarse en Scala como

for { 
    x <- List(1, 2, 3) 
    y <- List(7, 8, 9) 
    z = x + y 
} yield z 

Pero, sobre todo con las mónadas Haskell, Haskell tiene a menudo sentencias dentro del do bloque que no corresponde a <- o =. Por ejemplo, aquí hay un código de Pandoc que usa Parsec para analizar algo de una cadena.

-- | Parse contents of 'str' using 'parser' and return result. 
parseFromString :: GenParser tok st a -> [tok] -> GenParser tok st a 
parseFromString parser str = do 
    oldPos <- getPosition 
    oldInput <- getInput 
    setInput str 
    result <- parser 
    setInput oldInput 
    setPosition oldPos 
    return result 

Como se puede ver, se ahorra la posición y de entrada, se ejecuta el programa de análisis de la cadena, y luego restaura la entrada y la posición antes de devolver el resultado.

No puedo por la vida de mí averiguar cómo traducir setInput str, setInput oldInput y setPosition oldPos en Scala. Creo que funcionaría si acabo de poner las variables sin sentido en que yo pudiera usar <-, como

for { 
    oldPos <- getPosition 
    oldInput <- getInput 
    whyAmIHere <- setInput str 
    result <- parser 
    ... 
} yield result 

pero no estoy seguro de que sea el caso y, si es correcto, estoy seguro de que debe haber una mejor manera de hacer esto.

Ah, y si puede responder a esta pregunta, ¿puede responder una más: cuánto tiempo tengo para mirar a las Mónadas antes de que no se sientan como magia negra? :-)

Gracias! Todd

+7

Si no planea utilizar la variable, puede reemplazar su nombre con guión bajo: '_ <- setInput str' – incrop

+0

Supongo que esa es la manera más parecida a Scala de hacerlo. – TOB

+0

No estoy seguro de que sea realmente posible, pero esto podría parecer más natural al mover estas afirmaciones al cuerpo de la, donde realmente se puede ir al estilo de procedimiento. – dividebyzero

Respuesta

24

Sí, esa traducción es válida.

do { x <- m; n } es equivalente a m >>= \x -> n, y do { m; n } es equivalente a m >> n. Dado que m >> n se define como m >>= \_ -> n (donde _ significa "no enlazar este valor a nada"), es una traducción válida; do { m; n } es lo mismo que do { _ <- m; n }, o do { unusedVariable <- m; n }.

Una declaración sin un enlace variable en un bloque do simplemente ignora el resultado, generalmente porque no hay un resultado significativo del que hablar. Por ejemplo, no hay nada interesante que hacer con el resultado de putStrLn "Hello, world!", por lo que no vincularía su resultado a una variable.

(En cuanto a que las mónadas son magia negra, lo mejor que se puede tener es que no son realmente complicadas en absoluto; tratar de encontrar un significado más profundo en ellas no es generalmente una forma productiva de aprender cómo funcionan. Simplemente recomiendo leer el Typeclassopedia para obtener una comprensión sólida de las clases de tipos abstractos de Haskell, aunque deberá haber leído una introducción general de Haskell para sacarle provecho.

+1

¿Alguna idea de por qué Scala no proporciona azúcar para '>>'? –

+0

Creo que porque scala proporciona una comprensión de mónada en forma de. Tal vez el orden de los cálculos no se mantiene. Editar: No importa, parece que se mantiene. –

+1

La respuesta en Monad es realmente buena. Es solo un patrón de programación. Nada más que "magia negra". –