需要Javascript功能懒惰的评估示例解释

时间:2011-09-11 23:00:40

标签: javascript functional-programming lazy-evaluation

浏览Hacker News,我遇到了http://streamjs.org/,这是Javascript中懒惰评估集合的实现。

其中一个例子就是:

function ones() {  
    return new Stream( 1, ones );  
}  
function naturalNumbers() {  
    return new Stream(  
        // the natural numbers are the stream whose first element is 1...  
        1,  
        function () {  
            // and the rest are the natural numbers all incremented by one  
            // which is obtained by adding the stream of natural numbers...  
            // 1, 2, 3, 4, 5, ...  
            // to the infinite stream of ones...  
            // 1, 1, 1, 1, 1, ...  
            // yielding...  
            // 2, 3, 4, 5, 6, ...  
            // which indeed are the REST of the natural numbers after one  
            return ones().add( naturalNumbers() );  
        }   
    );  
}  
naturalNumbers().take( 5 ).print(); // prints 1, 2, 3, 4, 5

也许现在已经太晚了,我错过了这一点,但我不明白这是怎么打印1,2,3,4,5。我希望它能打印1,2,2,2,2并且无限深度递归。我理解ones将如何打印无限1.我不知道naturalNumbers如何工作。

通过我的(明显不正确的)逻辑,第一次调用head返回的Stream的{​​{1}}将为1,并且流中的下一个元素将被计算为{ {1}} naturalNumbers后面跟ones().add( naturalNumbers() );,它将重新转换为ones().add(1),依此类推......

如果有人对此有所了解,我会非常感激。

3 个答案:

答案 0 :(得分:11)

naturalNumbers[0] = 1 // by definition
naturalNumbers[1] = ones[0] + naturalNumbers[0] = 1 + 1 = 2
naturalNumbers[2] = ones[1] + naturalNumbers[1] = 1 + 2 = 3
naturalNumbers[3] = ones[2] + naturalNumbers[2] = 1 + 3 = 4
...

关键是function() { return ones().add(naturalNumbers()) }不返回元素,它返回。后续元素由该流生成,在这种情况下是“求和”流。因此,与ones()不同,naturalNumbers()不会直接调用自身。相反,它间接地调用自己 - 由求和流调解。

答案 1 :(得分:4)

好的,我会接受这个:)

ones是一个简单的起点。此函数返回Stream,其第一个值为1,其余值可以通过调用ones函数本身来计算。因此,对one值的“其余”值的任何请求都将始终以1开头,无限制。

接下来要看的是take函数:

function (howmany) {
    if (this.empty()) {
        return this;
    }
    if (howmany == 0) {
        return new Stream;
    }
    var self = this;
    return new Stream(this.head(), function () {
        return self.tail().take(howmany - 1);
    });
}

所以从上到下,如果Stream为空,那么请求了多少项无关紧要,因为无法满足该请求,所以Stream返回它(空的。自我。

如果我们没有请求任何项目,即howmany == 0,则会返回一个空的Stream,如果被要求,它本身不会产生任何项目。

最后是有趣的部分。对当前Stream的引用被锁定到函数范围中,并返回一个新的Stream。这个新的Stream创建时与当前Stream的头部相同,其尾部由一个函数创建,该函数将take与原始Stream相比减少一个项目尾巴比来电者要求。因此,当头部是一个项目并且尾部可以生成howmany-1个项目时,呼叫者将收到一个新的Stream,可能会提供所请求数量的项目。

naturalNumbers有点棘手。

naturalNumbers函数返回Stream作为其头部的1,以及一个生成其尾部的内部函数。

内部函数返回在add Stream上调用ones方法的结果,调用naturalNumbers函数的结果。所以我们可以猜测这涉及以某种方式将两个Stream“配对”。

添加什么样的?这是一个传递Stream

的函数
function (s) {
    return this.zip(function (x, y) {
        return x + y;
    }, s);
}

我们可以将'add'部分识别为内部函数 - 它将两个值一起添加,这样才有意义。但是zip做了什么? zip是一个函数,它接受一个函数并将Stream作为参数。

function (f, s) {
    if (this.empty()) {
        return s;
    }
    if (s.empty()) {
        return this;
    }
    var self = this;
    return new Stream(f(s.head(), this.head()), function () {
        return self.tail().zip(f, s.tail());
    });
}

所以在add的情况下,传入的函数是'add'(x + y)函数,StreamnaturalNumbers Stream

zip对这些值的作用是什么?如果Stream本身为空,则返回“其他”Stream。我想这是因为将[]添加到[2,4,6,8,...]比[2,3,6,8,...]更有意义。即第一个流被视为无限多0""

如果传入的Stream为空,则适用与上述相同的规则,反之亦然。即将[2,4,6,8,...]添加到[]。

现在有趣的部分。捕获对自身的引用后,将返回新的Stream。这个Stream由一个head值组成,它是应用于每个Stream的head元素的'add'函数,以及一个将'add'函数应用于每个Stream尾部的函数。 1}}如果需要的话。

因此,对于ones().add(naturalNumbers()),这将导致Stream的头部为2,因为使用1和{{调用'add'函数1}}(1ones的头元素都是naturalNumbers)。因此,如果要求将此新1添加到Stream,那么将ones头元素(始终为ones)添加到新1' s head元素(现为Stream),给出2

这个新3的尾部是一种在需要时提供更多“添加”的机制。

所以我们剩下的基本上是一种描述应用于头元素和尾部的操作的方法。只有当我们要求特定数量的物品时,我们才能通过机器生成这些物品。

因此,如果您调用了Stream,则需要大量资源,因为ones().take(9999999999999999999999999999999).print()函数需要才能在打印之前获得该值 - 这必然会导致此问题机器必须提供那么多print s。但1本身只是对头元素ones().take(9999999999999999999999999999999)的描述以及传递其余项目的过程,但仅在被要求时才会这样。

但是...... 我可能已经完全错了,因为我也迟到了,我只是读了这篇文章;)

答案 2 :(得分:3)

一次只执行一个学期的评估:

ones
= { 1, ones }
= { 1, { 1, ones } }
= ...
= { 1, { 1, { 1, ... to infinity!

nat
= { 1, ones+nat }
= { 1, { 1, ones } + { 1, ones+nat } } = { 1, { 1+1, ones+ones+nat } }
= { 1, { 2, { 1, ones } + { 1, ones } + { 1, nat } } }
= ...
= { 1, { 2, { 3, ... and so on.

http://streamjs.org底部的“筛子”示例更令人头疼,试试吧!