hFlush stdout

Learn You a Haskell for Great Good!を写経して学習しています。
以下のソースは Learn You a Haskell for Great Good! / 9 Input and Output / Exceptions を基に入力したファイルが存在しなかった場合はリトライするように書いたつもでした。

import System.Environment  
import System.IO  
import System.IO.Error  
  
-- この場合は File name: が表示される。
-- main = toTry 

main = toTry `catch` (\e -> toTry `catch` (\e -> toTry `catch` handler))

toTry :: IO ()
toTry = do 
      putStr "File name:"
      fileName <- getLine
      contents <- readFile fileName
      putStrLn $ "The file has " ++ show (length (lines contents)) ++ " lines!"
  

handler :: IOError -> IO ()  
handler e | isDoesNotExistError e = putStrLn "The file doesn't exist!"  
          | otherwise             = ioError e  
  • 1回で存在するファイル名が入力された場合。
$ runghc exception.hs
exception.hs    -- getLine に対する入力
File name:The file has 19 lines!
  • 3回ともで存在するファイル名が入力されなかった場合。
$ runghc exception.hs
abc    -- getLine に対する入力
hoge   -- getLine に対する入力
nnn    -- getLine に対する入力
File name:File name:File name:The file doesn't exist!

最後に File name: が出力されました。catchの中で出力するのではなく、これを出力してね、という手続きを返すからなのでしょう。

  • 追記 2011/06/18:hFlush stdout を入れて解決しました。
import System.Environment  
import System.IO  
import System.IO.Error  
  
main = toTry `catch` (\e -> toTry `catch` (\e -> toTry `catch` handler))

toTry :: IO ()
toTry = do 
      putStr "File name:"
      hFlush stdout -- ※これを入れることで解決。
      fileName <- getLine
      contents <- readFile fileName
      putStrLn $ "The file has " ++ show (length (lines contents)) ++ " lines!"
  

handler :: IOError -> IO ()  
handler e | isDoesNotExistError e = putStrLn "The file doesn't exist!"  
          | otherwise             = ioError e  
$ runghc exception.hs
File name:hoge
File name:huga
File name:exception.hs
The file has 21 lines!