代码之家  ›  专栏  ›  技术社区  ›  dmg

懒散,单词是读(交互)所有的输入,还是只需要什么?

  •  0
  • dmg  · 技术社区  · 7 年前

    我开始学习哈斯凯尔,我试图理解 这些功能做了多少工作(特别是关于 懒惰的概念)。请参阅以下程序:

    main::IO()
    main = interact ( head . words)
    

    这个程序将读取所有输入还是只读取输入中的第一个字?

    2 回复  |  直到 7 年前
        1
  •  3
  •   Daniel Wagner    7 年前

    只是第一个词:

    % yes | ghc -e 'interact (head . words)'
    y
    %
    

    但是要注意:这依赖于一个称为“lazy io”的特性,它只与纯代码中的lazy技术有关。纯函数在默认情况下是懒惰的,您必须努力使其严格;IO在默认情况下是“严格IO”,您必须努力使其懒惰IO。一些库函数(尤其是 interact , (h)getContents readFile )已经努力了。

    It also has some problems with composability.

        2
  •  3
  •   Yann Vernier    7 年前

    从概念上讲,它只读取它需要的内容。但它可能使用缓冲区来实现这一点:

    $ 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读取8kb数据,然后另一个线程输出第一个字。主要原因是反复阅读少量的内容是非常低效的。异步源(如终端和套接字)可能会产生较小的数据量,但:

    $ 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大。因为这足够识别第一个单词的数据,所以不需要进一步读取。