为什么以下程序不打印我的输入?似乎putStr
没有接受输入。 getContents
如何运作?
main = do
contents <- getContents
when (length contents < 10) $ putStr contents
但是,该程序逐行打印输入:
main = do
contents <- getContents
putStr contents
答案 0 :(得分:10)
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返回值。对于列表(注意,String
是Char
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或关闭应用程序,然后才能看到结果。