You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用runhaskell时如何确保Haskell do块按顺序执行?

Why does runhaskell execute getLine before putStr in my Haskell IO code?

Great question! This is a classic issue tied to standard output buffering in Haskell, and it comes down to how GHC handles IO differently in interactive vs non-interactive environments.

Let's break down what's happening first. Your code looks like this:

main = do
  putStr "Enter Some Text: "
  text <- getLine
  writeFile "text.txt" text
  putStrLn "Updated!"

When you run this in GHCi, it behaves exactly as expected: it shows the prompt, waits for your input, writes to the file, then prints the success message. But with runhaskell, you see this out-of-order behavior:

runhaskell EditFile.hs
hello
Enter Some Text: Updated!

The Root Cause

GHC uses different buffering strategies by default depending on whether it's in an interactive session (like GHCi) or running a compiled/interpreted program non-interactively (like runhaskell):

  • In GHCi, standard output uses line buffering, and it automatically flushes the buffer when waiting for input. That's why your putStr prompt shows up right away.
  • With runhaskell, standard output defaults to block buffering. Since putStr "Enter Some Text: " doesn't end with a newline, the text gets stuck in the output buffer. The program waits for your input via getLine first, and only when the buffer is flushed (either by the newline in putStrLn or when the program exits) does the prompt finally show up—along with the success message.

Fixes to Try

Here are three straightforward ways to fix this, depending on your needs:

1. Manually Flush the Buffer

The most direct fix is to force the output buffer to flush right after your putStr call. You'll need to import System.IO to use hFlush:

import System.IO

main = do
  putStr "Enter Some Text: "
  hFlush stdout  -- Push the prompt out of the buffer immediately
  text <- getLine
  writeFile "text.txt" text
  putStrLn "Updated!"

2. Use putStrLn (If a Newline Is Acceptable)

If you don't mind the prompt being on its own line, swap putStr for putStrLn. putStrLn automatically adds a newline and flushes the buffer, so your prompt will show up before input is requested:

main = do
  putStrLn "Enter Some Text:"
  text <- getLine
  writeFile "text.txt" text
  putStrLn "Updated!"

3. Set Global Line Buffering

If you have multiple places in your code where you need unbuffered or line-buffered output, you can set the buffering mode for stdout once at the start of your program:

import System.IO

main = do
  hSetBuffering stdout LineBuffering  -- Make all output line-buffered
  putStr "Enter Some Text: "
  text <- getLine
  writeFile "text.txt" text
  putStrLn "Updated!"

This ensures that any output (even without a newline) will be flushed as soon as a line is complete, or when waiting for input—just like in GHCi.

内容的提问来源于stack exchange,提问作者E2718

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 04:36:46