使用getChar重新实现getContents

joh*_*ink 6 haskell lazy-io

在我对Haskell中抓住懒惰IO的哀悼中,我尝试了以下方法:

main = do
  chars <- getContents
  consume chars

consume :: [Char] -> IO ()
consume [] = return ()
consume ('x':_) = consume []
consume (c : rest) = do
  putChar c
  consume rest
Run Code Online (Sandbox Code Playgroud)

它只是回显了所有在stdin中键入的字符,直到我点击'x'.

所以,我天真地认为应该可以getContents通过getChar以下几点做一些事情来重新实现:

myGetContents :: IO [Char]
myGetContents = do
  c <- getChar
  -- And now?
  return (c: ???) 
Run Code Online (Sandbox Code Playgroud)

事实证明它不是那么简单,因为它???需要一个类型的功能IO [Char] -> [Char]- 我认为 - 打破IO monad的整个想法.

检查getContents(或更确切地说hGetContents)的实施揭示了整个香肠工厂的脏IO东西.我的假设是否正确,myGetContents如果不使用脏的,即monad-breaking代码, 就无法实现?

Rei*_*ton 6

您需要一个新的原语unsafeInterleaveIO :: IO a -> IO a来延迟其参数操作的执行,直到评估该操作的结果.然后

myGetContents :: IO [Char]
myGetContents = do
  c <- getChar
  rest <- unsafeInterleaveIO myGetContents
  return (c : rest)
Run Code Online (Sandbox Code Playgroud)

  • 像魅力一样工作:)仍然要补充说`unsafeInterleaveIO`必须从`System.IO.Unsafe`导入. (3认同)