CODEONWORT

putStr이 제 때 출력을 하지 않아요 본문

Season 1/하스켈

putStr이 제 때 출력을 하지 않아요

codeonwort 2014.10.27 07:36
하스켈은 간단한 로직을 라이브러리 함수로 제공하는 경우가 많아서 뭘 만들려다보면 직접 만들어야 하는지 문서에서 찾아봐야 하는지 모르겠다 -_-

암튼 실행 파일을 만들어보고자 처음으로 GHCi를 실행해서 숫자를 맞추는 간단한 게임을 구현해봤다. loop라는 보조 함수를 구현했는데 인자를 받아서 루프를 계속 돌거나 중단할 수 있는 기능이 있다.

import System.IO

main = loop 50 $ \goal -> do
  putStr "Enter your guess: "
  input <- getLine
  let n = read input :: Int
  if n == goal
    then putStrLn "Yes!" >> return (True, goal)
    else if n > goal
      then putStrLn "High!" >> return (False, goal)
      else putStrLn "Low!" >> return (False, goal)

loop :: a -> (a -> IO (Bool, a)) -> IO a
loop arg callback = do
  result <- callback arg
  case result of
    (True, a) -> return a
    (False, a) -> loop a callback

GHCi에서 인터프리터로 한 번 실행해보고 문제가 없어서 컴파일을 했더니 드디어 하스켈로 처음으로 만든 .exe 파일이 생겼다. 근데..

-- 실행 결과
20
Enter your guess: Low!


???

-- 인터프리터에서 실행한 올바른 결과
Enter your guess: 20
Low! 


머여 이건 -_- 왜 결과가 다른데

검색해보니 간단한 문제였는데(http://www.haskell.org/pipermail/haskell/2006-September/018430.html), 컴파일된 프로그램에서는 표준 출력 버퍼에 라인 버퍼링을 적용해서 \n이 나오지 않을 때까지 쌓아둔다고 한다. 그러니까 putStrLn은 실행할 때마다 재깍재깍 출력이 되지만 putStr은 안 된다는 소린데, 강제로 출력하면 된다. putStr 바로 다음에 hFlush stdout을 호출하자.

import System.IO

main = loop 50 $ \goal -> do
  putStr "Enter your guess: "
  hFlush stdout 
  input <- getLine
  let n = read input :: Int
  if n == goal
    then putStrLn "Yes!" >> return (True, goal)
    else if n > goal
      then putStrLn "High!" >> return (False, goal)
      else putStrLn "Low!" >> return (False, goal)

loop :: a -> (a -> IO (Bool, a)) -> IO a
loop arg callback = do
  result <- callback arg
  case result of
    (True, a) -> return a
    (False, a) -> loop a callback

0 Comments
댓글쓰기 폼