Haskell:getContents如何工作?

时间:2014-01-17 15:16:54

标签: haskell io

为什么以下程序不打印我的输入?似乎putStr没有接受输入。 getContents如何运作?

main = do 
    contents <- getContents
    when (length contents < 10) $ putStr contents    

但是,该程序逐行打印输入:

main = do 
    contents <- getContents
    putStr contents    

3 个答案:

答案 0 :(得分:10)

getContents获取所有内容。线路缓冲使其逐行

getContents从句柄中获取整个输入(例如文件或用户输入),因此您的程序

main = do 
    contents <- getContents
    putStr contents

读取标准输入的全部内容并打印出来。你逐行看到这一点的唯一原因是它在终端上使用了线路缓冲,所以getContents当时将其传入的字符串变为一行。

懒惰评估

Haskell使用延迟评估,这意味着它只会在必要时计算某些内容 - 它不会需要计算要打印的字符串的结尾以打印它的开头,所以它不打扰,只打印现在的东西。这些惰性函数能够在可能的情况下返回部分结果,而不必首先计算所有内容。

一次一行

您在评论中看到只想在此会话期间缩短行时打印行:

don't print this it's long
print this
print this
this is also too long
boo!
boo!    

但由于getContents 全部输入,除非长度小于10,否则不会打印任何内容。您所追求的是什么它分别处理每一行,更像是

main = do
  contents <- getContents
  putStrLn . unlines . filter short . lines $ contents

short xs = length xs <= 10

答案 1 :(得分:3)

getContents读取所有stdin,但它的工作原理很懒散。它返回一个thunk,它是一个承诺,当你提出它时会返回一些值(强迫thunk)。

putStr一次要求一个字符,强制thunk返回值。对于列表(注意,StringChar s的列表),当强制返回时,thunk返回“end of of list”或对(“next char”,“thunk for the list of list) “)。所以第二个例子有效,因为putStr在可用时输出字符。您输入下一行 - putStr输出char-by-char,尝试强制下一个thunk,但阻塞因为下一个char尚未可用。

第一个例子强制thunk直到它返回“list of end”,因为在它可用之前不可能知道字符串长度。

答案 2 :(得分:1)

如果您正在进行交互式应用程序,那么获取getContents的长度是一个坏主意。这是因为标准输入的长度只能在流关闭时计算。这意味着您必须在Linux上使用Ctrl + D,在Windows上使用Ctrl + Z或关闭应用程序,然后才能看到结果。