usar simbolos programa librerias instancias importar ejemplos definir datos data contador como haskell user-input monads

simbolos - instancias en haskell



IO sucede fuera de orden al usar getLine y putStr (3)

Soy un principiante de Haskell, apenas estoy empezando a envolver mi cabeza alrededor de Monads, pero todavía no lo entiendo. Estoy escribiendo un juego que consiste en pedirle al usuario su opinión y responder. Aquí está una versión simplificada de mi función:

getPoint :: IO Point getPoint = do putStr "Enter x: " xStr <- getLine putStr "Enter y: " yStr <- getLine return $ Point (read xStr) (read yStr) completeUserTurn :: (Board, Player) -> IO (Board, Player) completeUserTurn (board, player) = do putStr $ "Enter some value: " var1 <- getLine putStr $ "Enter another value: " var2 <- getLine putStr $ "Enter a point this time: " point <- getPoint if (... the player entered legal values ...) then do putStr $ "This is what would happen if you did that: {stuff} do you want to do that? (y/n) " continue <- getLine if continue == "y" then return (...updated board..., ...updated player...) else completeUserTurn (board, player) else do putStr "Invalid Move!/n" completeUserTurn (board, player)

Lo que está sucediendo es que las indicaciones aparecerán desordenadas con el texto que debe aparecer antes de la solicitud.

Aquí hay un ejemplo de lo que está pasando después de que compilé el código anterior:

1
Ingrese algún valor: Ingrese otro valor: 2
3
4
Ingrese un punto esta vez: Ingrese x: Ingrese y: y
¿Es esto correcto? (y / n):

Las negritas son las cosas que escribí.

Obviamente, tengo un error conceptual importante, pero no sé qué. Tenga en cuenta que funciona correctamente en el intérprete y falla cuando se compila.


Como dijo Michael, el problema es amortiguar. De forma predeterminada, la salida se almacena en búfer hasta que imprime una nueva línea (o hasta que el búfer está lleno si tiene líneas realmente largas), por lo que la mayoría de las veces verá este problema cuando intente hacer indicaciones en la misma línea usando putStr como lo está haciendo. .

Sugiero que defina una pequeña función de ayuda como esta para encargarse de hacer el lavado por usted:

import System.IO prompt :: String -> IO String prompt text = do putStr text hFlush stdout getLine

Ahora puedes simplemente hacer

getPoint = do xStr <- prompt "Enter x: " yStr <- prompt "Enter y: " return $ Point (read xStr) (read yStr)


El IO está sucediendo en el orden correcto. El problema es el almacenamiento en búfer. Si elimina la salida estándar después de cada putStr, debería funcionar como se esperaba. Deberá importar hFlush y stdout desde System.IO .


El problema no fue con el orden de las operaciones en el código IO. El problema fue que la entrada y la salida están almacenadas de manera predeterminada en el búfer cuando se usan stdin y stdout. Esto aumenta el rendimiento de IO en una aplicación, pero puede hacer que las operaciones parezcan desordenadas cuando se usan tanto stdin como stdout.

Hay dos soluciones para esto. Puede usar el método hFlush para forzar la hFlush de un tirador (ya sea estándar o estándar). Por ejemplo, hFlush stdout , hFlush stdin . Una solución más simple (que funciona bien para aplicaciones interactivas) es deshabilitar el almacenamiento en búfer por completo. Puede hacer esto llamando a los métodos hSetBuffering stdout NoBuffering y hSetBuffering stdin NoBuffering antes de iniciar su programa (es decir, ponga esas líneas en su método principal.