对无限IO动作序列执行sequence是否会无限运行?能否提前终止?
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 getCharcreates an infinite list ofIO Charactions, each representing a single character read.sequenceexists to run all actions in the list sequentially, collect every result into a single list, and only then return that list. This meanssequencewill keep runninggetCharforever (or until the program is killed externally), never givingtakeWhilea 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—sequencemust execute every action before returning any results. - Lazy IO can achieve this, but it's unsafe and not recommended.
- Stick to recursion or
unfoldrMfor predictable, idiomatic IO control flow.
Content sourced from Stack Exchange, question author: Enlico

