【问题标题】:lazyness, does words read (within interact) all the input, or only what is needed?懒惰,单词是否读取(在交互中)所有输入,还是只读取需要的内容?
【发布时间】:2018-05-23 23:37:01
【问题描述】:

我开始学习 Haskell,我正在努力理解 这些功能做了多少工作(特别是关于 懒惰的概念)。请看以下程序:

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

这个程序会读取所有输入还是只读取输入中的第一个单词?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    只是第一个词:

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

    但请注意:这依赖于一个称为“惰性 IO”的功能,它仅与纯代码中的惰性技术有关。纯函数默认是惰性的,你必须努力使它们变得严格; IO 默认是“严格 IO”,你必须努力让它成为惰性 IO。一些库函数(特别是 interact(h)getContentsreadFile)已经参与了这项工作。

    It also has some problems with composability.

    【讨论】:

    • 谢谢。我也很欣赏答案的深度,包括如何测试它。
    【解决方案2】:

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-15
      • 2016-02-19
      • 2012-11-15
      • 2022-11-21
      • 2012-04-07
      • 1970-01-01
      相关资源
      最近更新 更多