2015-11-30 17 views
5

ich den folgenden Code haben:Haskell IO Ausführungsreihenfolge

import Control.Monad (unless) 
import System.IO (isEOF, hFlush, stdout) 

main :: IO() 
main = unlessFinished $ do 
     putStr "$ " 
     hFlush stdout 
     getLine >>= putStrLn 
     main 
    where 
    unlessFinished action = isEOF >>= flip unless action 

Wenn ich diesen Code kompilieren und ausführen, zeigt es einen Cursor am Anfang der Leerzeile und erst nachdem ich [Enter] it Ausgänge $ und was auch immer ich geschrieben hatte.

Es scheint, dass getLine vor putStr "$ " obwohl IO Monade Garantien aufgerufen wird, dass es die Aktionen in der Reihenfolge aufgerufen werden sie im Code sequenziert sind (oder so verstehe ich, was here geschrieben). Warum funktioniert es nicht richtig?

+1

By the way, ich habe eigentlich nicht, dass Sie glauben, bis ich den Code selbst versucht läuft. Dann sagte ich tatsächlich "whaaaaa ...?!" laut in meiner Kabine. Nette Arbeit, die deine Frage in eine so schöne, verdauliche, überraschende Form bringt! –

+0

Danke. Es war auch für mich überraschend. Eigentlich fing ich an zu glauben, dass es nicht Haskells "Fehler" ist, sondern eine andere Shell/Terminal/OS-Falle, von der ich vorher nichts wusste. :) – Sventimir

Antwort

9

Eigentlich sind die putStr und hFlush Aktionen sind ausgeführt wird, bevor die getLine Aktion - jedoch wird isEOF bevor entweder ausgeführt wird, und es nicht zurück, bis er weiß, ob der Eingang EOF ist oder nicht, das ist , bis Sie eine Zeile eingeben. Sie betrachten könnte die isEOF nach rechts vor dem getLine, wie diese bewegen:

main :: IO() 
main = do 
    putStr "$ " 
    hFlush stdout 
    unlessFinished $ do 
     getLine >>= putStrLn 
     main 
    where 
    unlessFinished action = isEOF >>= flip unless action 
+0

Auffallend einfache Erklärung! Ich frage mich schon, wie ich nicht selbst daran denken könnte. Es stellt sich heraus, dass Haskell noch mehr Fallen hat, als ich erwartet hatte. Danke vielmals. :) – Sventimir