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

对无限IO动作序列执行sequence是否会无限运行?能否提前终止?

Answer

First, you're right—there's no idiomatic way to early exit from the IO [Char] produced by sequence (repeat getChar). Here's why:

  • repeat getChar creates an infinite list of IO Char actions, each representing a single character read.
  • sequence exists to run all actions in the list sequentially, collect every result into a single list, and only then return that list. This means sequence will keep running getChar forever (or until the program is killed externally), never giving takeWhile a chance to process the results—since it has to finish every action first.

If you insist on building around the idea of sequence (repeat getChar), you can use lazy IO as a workaround, but this is not recommended in idiomatic Haskell because it breaks the predictability of IO operations. For example:

import System.IO.Unsafe (unsafeInterleaveIO)

main :: IO ()
main = do
  let infiniteChars = unsafeInterleaveIO $ (:) <$> getChar <*> infiniteChars
  x <- takeWhile (/= 'q') <$> infiniteChars
  print "you pressed q"

unsafeInterleaveIO makes the IO execution lazy: each getChar runs only when we need the next element of the list. This lets takeWhile stop as soon as it hits 'q'. But be warned—unsafeInterleaveIO is unsafe because it violates Haskell's strict IO ordering, leading to unpredictable behavior in real-world code.

The idiomatic solution is to abandon the sequence (repeat getChar) approach entirely, and use recursion or a helper function like unfoldrM instead:

Using unfoldrM

import Control.Monad (unfoldrM)

main :: IO ()
main = do
  _ <- unfoldrM (\() -> do
                   c <- getChar
                   pure $ if c == 'q' then Nothing else Just (c, ())) ()
  print "you pressed q"

Using direct recursion

main :: IO ()
main = go []
  where
    go acc = do
      c <- getChar
      if c == 'q'
        then print "you pressed q"
        else go (c : acc)

Key Takeaways

  • Idiomatic early exit from sequence (repeat getChar) is impossible—sequence must execute every action before returning any results.
  • Lazy IO can achieve this, but it's unsafe and not recommended.
  • Stick to recursion or unfoldrM for predictable, idiomatic IO control flow.

Content sourced from Stack Exchange, question author: Enlico

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 21:12:33