我开始学习Haskell,我正在努力理解 这些功能做了多少工作(特别是关于 懒惰的概念)。请参阅以下程序:
main::IO()
main = interact ( head . words)
这个程序会读取输入中的所有输入还是只读取第一个单词?
答案 0 :(得分:3)
只是第一个字:
% yes | ghc -e 'interact (head . words)'
y
%
但要注意:这依赖于一个名为"懒惰的IO"这只与纯代码中的懒惰技术有关。纯函数在默认情况下是懒惰的,你必须努力使它们严格; IO是严格的IO"默认情况下,你必须努力使其懒惰IO。少数库函数(特别是interact
,(h)getContents
和readFile
)已经付出了这些努力。
答案 1 :(得分:3)
从概念上讲,它只读取它所需要的内容。但它可能使用缓冲区来执行此操作:
$ yes | strace -feread,write ghc -e 'interact (head . words)'
...
[pid 61274] read(0, "y\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\ny\n"..., 8096) = 8096
[pid 61272] write(1, "y", 1y) = 1
[pid 61272] --- SIGVTALRM {si_signo=SIGVTALRM, si_code=SI_TIMER, si_timerid=0, si_overrun=0, si_value={int=0, ptr=0}} ---
[pid 61272] write(5, "\376", 1) = 1
[pid 61273] read(4, "\376", 1) = 1
[pid 61273] +++ exited with 0 +++
[pid 61274] +++ exited with 0 +++
[pid 61276] +++ exited with 0 +++
+++ exited with 0 +++
这表明(在Linux系统上)程序将自己分成多个线程,其中一个从stdin读取8KiB数据,然后另一个输出第一个字。主要原因是反复阅读少量是非常低效的。但是,终端和套接字等异步源可能会产生较少量的数据:
$ strace -f -e trace=read,write -e signal= ghc -e 'interact (head . words)'
...
hello program
Process 61594 attached
[pid 61592] read(0, "hello program\n", 8096) = 14
[pid 61590] write(1, "hello", 5hello) = 5
在这种情况下,终端层在第一个换行符处完成读取,即使缓冲区仍然是8KiB大。由于这足以确定第一个单词的数据,因此无需进一步读取。