# 4.2.3流作为惰性列表

> 译者： [https://sicp.comp.nus.edu.sg/chapters/84](https://sicp.comp.nus.edu.sg/chapters/84)

在 [3.5.1](67)承诺&lt;/quote&gt;来计算流的`tail`，直到稍后才真正实现该承诺。 我们被迫将流创建为一种与列表相似但不相同的新型数据对象，这要求我们重新实现许多普通的列表操作（`map`，`append`等）以用于流。

使用惰性评估，流和列表可以相同，因此不需要单独的列表和流操作。 我们要做的就是安排事务，以使`pair`不受限制。 实现此目的的一种方法是扩展惰性评估器以允许使用非严格原语，并将`pair`实现为其中之一。 一种更简单的方法是回想一下（ [2.1.3](27) 节），根本不需要将`pair`实现为原语。 相反，我们可以将对表示为函数： [[1]](84#footnote-1)

```js
function pair(x, y) {	
    return m => m(x, y);
}
function head(z) {    
    return z( (p, q) => p );
}
function tail(z) {
    return z( (p, q) => q );
}
```

就这些基本操作而言，列表操作的标准定义将与无限列表（流）以及有限列表（流）一起使用，并且流操作可以实现为列表操作。 这里有些例子：

```js
function list_ref(items, n) {	
    return n === 0
           ? head(items)
           : list_ref(tail(items), n - 1);
}
function map(fun, items) {	   
    return is_null(items)
           ? null
           : pair(fun(head(items)),
                  map(fun, tail(items)));
}
function scale_list(items, factor) {
    return map(x => x * factor, items);
}
function add_lists(list1, list2) {
    return is_null(list1)
           ? list2
           : is_null(list2)    
             ? list1
             : pair(head(list1) + head(list2),
                    add_lists(tail(list1),
                              tail(list2)));
}
const ones = pair(1, ones);
const integers = pair(1, add_lists(ones, integers));

list_ref(integers, 17); // returns 18
```

请注意，这些惰性列表甚至比第3章的流更懒惰：列表的`head`以及`tail`被延迟。 [[2]](84#footnote-2) 实际上，即使访问惰性对的`head`或`tail`也无需强制使用列表元素的值。 该值仅在确实需要时才被强制使用-例如，用作基元的自变量，或打印为答案。

懒散对还有助于解决 [3.5.4](70)[3.5.4](70) 部分的原意实现用于集成列表和求解微分方程的函数：

```js
function integral(integrand, initial_value, dt) {	
    const int =
        pair(initial_value,
             add_lists(scale_list(integrand, dt),
                       int));
    return int;
}
function solve(f, y0, dt) {
    const y = integral(dy, y0, dt);
    const dy = map(f, y);
    return y;
}
list_ref(solve(x => x, 1, 0.001), 1000);
```

<exercise>Give some examples that illustrate the difference between the streams of chapter 3 and the <quote>lazier</quote> lazy lists described in this section. How can you take advantage of this extra laziness?<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#no_solution_84_1_div">Add solution</button>There is currently no solution available for this exercise. This textbook adaptation is a community effort. Do consider contributing by providing a solution for this exercise, using a Pull Request in [Github](https://github.com/source-academy/sicp).</exercise><exercise>Ben Bitdiddle tests the lazy list implementation given above by evaluating the expression

```js
head(list(a, b, c));
```

To his surprise, this produces an error. After some thought, he realizes that the <quote>lists</quote> obtained by reading in quoted expressions are different from the lists manipulated by the new definitions of `pair`, `head`, and `tail`. Modify the evaluator's treatment of applications of the primitive function l `list` typed at the driver loop will produce true lazy lists.<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#no_solution_84_1_div">Add solution</button>There is currently no solution available for this exercise. This textbook adaptation is a community effort. Do consider contributing by providing a solution for this exercise, using a Pull Request in [Github](https://github.com/source-academy/sicp).</exercise><exercise>Modify the driver loop for the evaluator so that lazy pairs and lists will print in some reasonable way. (What are you going to do about infinite lists?) You may also need to modify the representation of lazy pairs so that the evaluator can identify them in order to print them.<button class="btn btn-secondary solution_btn" data-toggle="collapse" href="#no_solution_84_1_div">Add solution</button>There is currently no solution available for this exercise. This textbook adaptation is a community effort. Do consider contributing by providing a solution for this exercise, using a Pull Request in [Github](https://github.com/source-academy/sicp).</exercise>

* * *

[[1]](84#footnote-link-1) This is the functional representation described in exercise <ref name="ex:lambda-cons">[2.4](27#ex_2.4)</ref>. Essentially any functional representation (e.g., a message-passing implementation) would do as well. Notice that we can install these definitions in the lazy evaluator simply by typing them at the driver loop. If we had originally included `pair`, `head`, and `tail` as primitives in the global environment, they will be redefined. (Also see exercises <ref name="ex:lazy-list-input">[4.24](84#ex_4.24)</ref> and <ref name="ex:lazy-list-printing">[4.25](84#ex_4.25)</ref>.)

[[2]](84#footnote-link-2) This permits us to create delayed versions of more general kinds of list structures, not just sequences. <citation>Hughes 1990</citation> discusses some applications of <quote>lazy trees.</quote>

