2015-11-30 16 views
5

Mam następujący kod:kolejność wykonywania Haskell IO

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 

Kiedy skompilować i uruchomić ten kod, to wyświetla kursor na początku pustej linii i dopiero po I hit [Enter] go wyprowadza $ i cokolwiek napisałem.

Wydaje się, że getLine jest wywoływana przed putStr "$ " nawet tych IO gwarancji monady, że to działania są nazywane w kolejności są one sekwencjonowanym w kodzie (przynajmniej tak mi zrozumieć, co jest napisane here). Dlaczego więc nie działa poprawnie?

+1

nawiasem mówiąc, tak naprawdę nie wierzył, dopóki próbowałem uruchomieniem kodu siebie. Wtedy rzeczywiście powiedziałem "co ...?!" głośno w mojej klitce. Niezła robota, oddająca twoje pytanie w tak ładną, strawną, zaskakującą formę! –

+0

Dziękuję. Zaskoczyło mnie to również. Właściwie to zaczynałem wierzyć, że to nie "wina" Haskella, ale jakaś inna pułapka powłoki/terminalu/OS, o której wcześniej nie wiedziałem. :) – Sventimir

Odpowiedz

9

Faktycznie, putStr i hFlush działania wykonywane przed akcja getLine - jednak isEOF jest wykonywany przed albo i nie powróci, dopóki nie wie, czy wejście jest EOF czy nie, to jest , dopóki nie wprowadzisz linii. Można rozważyć przeniesienie isEOF do prawej strony przed getLine, tak:

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

Zadziwiająco proste wyjaśnienie! Zastanawiam się już, jak mogłem sam o tym nie myśleć. Okazuje się, że Haskell ma dla mnie więcej pułapek, niż się spodziewałem. Wielkie dzięki. :) – Sventimir