2010-04-24 25 views
5

Tengo un problema con IO no se ejecuta en orden, incluso dentro de una construcción do.¿Por qué mi IO no se ejecuta en orden?

En el siguiente código solo estoy haciendo un seguimiento de las tarjetas que quedan, donde la tarjeta es una tupla de caracteres (uno para el palo y el otro para el valor), luego se le pregunta continuamente qué tarjetas se han jugado. Quiero que el putStr se ejecute entre cada entrada, y no al final como ahora.

module Main where 
main = doLoop cards 
doLoop xs = do putStr $ show xs 
       s <- getChar 
       n <- getChar 
       doLoop $ remove (s,n) xs 
suits = "SCDH" 
vals = "A23456789JQK" 
cards = [(s,n) | s <- suits, n <- vals] 
type Card = (Char,Char) 
remove :: Card -> [Card] -> [Card] 
remove card xs = filter (/= card) xs 

Respuesta

8

La respuesta de Absz es correcta, el IO con búfer de Haskell es lo que le está causando problemas. He aquí una manera de reescribir su doLoop tener el efecto que buscas:

doLoop xs = do putStrLn $ show xs 
       input <- getLine 
       let s:n:_ = input 
       doLoop $ remove (s,n) xs 

Los dos cambios: utilizar putStrLn para añadir un salto de línea y enjuagar la salida (que es probablemente lo que quiere), y el uso de getLine agarrar la entrada una línea a la vez (de nuevo, probablemente lo que quieras).

+0

¡Código incorrecto! Aquí introduce una falla de coincidencia de patrón potentiel. –

+0

Es cierto que el caso no es exhaustivo, pero como una prueba de concepto (con respecto a las operaciones IO) hace el trabajo. – perimosocordiae

14

Si el problema es lo que yo creo que es, su problema es que IO de Haskell es amortiguada: this question explica lo que está pasando. Cuando ejecuta un programa Haskell compilado, GHC almacena la salida en el búfer y solo la vacía periódicamente en la pantalla; lo hace si (a) el búfer está demasiado lleno, (b) si se imprime una nueva línea, o (c) si llama al hFlush stdout.

El otro problema que puede estar viendo es que getChar no se puede disparar hasta que se lea una nueva línea, pero entonces la nueva línea está en su flujo de entrada; quizás puedas resolver esto con un getChar extra para tragar la nueva línea, pero probablemente debería haber una forma mejor.

+0

Sí, buena llamada. Solo lo intenté yo mismo; funciona bien en GHCi, no imprime nada hasta el final cuando se compila, al igual que la pregunta a la que se vinculó. –

6

El almacenamiento en búfer, en forma de putStr, es su problema, como han señalado otros.

Además, un punto de estilo: putStrLn $ show xs es la misma que print xs

Cuestiones relacionadas