2010-04-24 7 views
5

Ho riscontrato un problema con I/O non in esecuzione in ordine, anche all'interno di un costrutto do.Perché il mio IO non viene eseguito in ordine?

Nel seguente codice mi limito a tenere traccia di quali carte sono rimaste, dove la carta è una tupla di caratteri (una per seme e una per valore) quindi all'utente viene chiesto continuamente quali carte sono state giocate. Voglio che il putStr sia eseguito tra ogni input e non alla fine come ora.

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 

risposta

8

La risposta di absz è corretta, l'IO bufferizzato di Haskell è ciò che ti causa problemi. Ecco un modo per riscrivere il doLoop per avere l'effetto che stai cercando:

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

Le due modifiche: utilizzare putStrLn per aggiungere una nuova riga e sciacquare l'uscita (che è probabilmente quello che si vuole), e utilizzare getLine per prendere l'input una linea alla volta (di nuovo, probabilmente quello che vuoi).

+0

Codice errato! Qui si presenta un errore di corrispondenza del modello potenzioso. –

+0

È vero, il caso è tutt'altro che esaustivo, ma come prova del concetto (per quanto riguarda le operazioni di IO) fa il lavoro. – perimosocordiae

14

Se il problema è quello che penso che sia, il problema è che IO Haskell è tamponato: this question spiega cosa sta succedendo. Quando si esegue un programma Haskell compilato, GHC memorizza l'output nel buffer e lo scarica periodicamente sullo schermo; lo fa se (a) il buffer è troppo pieno, (b) se viene stampata una nuova riga o (c) se si chiama hFlush stdout.

L'altro problema che si può vedere è che getChar non può essere attivato finché non viene letto un carattere di ritorno a capo, ma la nuova riga si trova nel flusso di input; potresti forse risolvere questo con un extra getChar per ingoiare il newline, ma probabilmente dovrebbe esserci un modo migliore.

+0

Yep, buona chiamata. Ho appena provato da solo; funziona bene con GHCi, non stampa nulla fino alla fine quando compilato, proprio come la domanda a cui ti sei collegato. –

6

Buffering, sotto forma di putStr, è il tuo problema, come altri hanno sottolineato.

Inoltre, un punto di stile: putStrLn $ show xs è lo stesso di print xs