细心的读者会发现为什么新构造的stream的第二参数是一个返回尾部的函数、而不是尾部本身的原因了。这种方式可以通过延迟尾部截取的操作来防止进行进入无穷尽的执行周期。
让我们来看一个更复杂的例子。下面的是给读者留下的一个练习,请指出下面这段代码是做什么的?
- function sieve( s ) {
- var h = s.head();
- return new Stream( h, function () {
- return sieve( s.tail().filter( function( x ) {
- return x % h != 0;
- } ) );
- } );
- }
- sieve( Stream.range( 2 ) ).take( 10 ).print();
请一定要花些时间能清楚这段代码的用途。除非有函数式编程经验,大多数的程序员都会发现这段代码很难理解,所以,如果你不能立刻看出来,不要觉 得沮丧。给你一点提示:找出被打印的stream的头元素是什么。然后找出第二个元素是什么(余下的元素的头元素);然后第三个元素,然后第四个。这个函 数的名称也能给你一些提示。如果你对这种难题感兴趣,这儿还有一些。
如果你真的想不出这段代码是做什么的,你就运行一下它,自己看一看!这样你就很容易理解它是怎么做的了。
致敬
Streams 实际上不是一个新的想法。很多的函数式的编程语言都支持这种特征。所谓‘stream’是Scheme语言里的叫法,Scheme是LISP语言的一种方言。Haskell语言也支持无限大列表(list)。这些'take', 'tail', 'head', 'map' 和 'filter' 名字都来自于Haskell语言。Python和其它很多中语言中也存在虽然不同但很相似的这种概念,它们都被称作"发生器(generators)"。
这些思想来函数式编程社区里已经流传了很久了。然而,对于大多数的Javascript程序员来说却是一个很新的概念,特别是那些没有函数式编程经验的人。
这里很多的例子和创意都是来自Structure and Interpretation of Computer Programs这本数。如果你喜欢这些想法,我高度推荐你读一读它;这本书可以在网上免费获得。它也是我开发这个Javascript类库的创意来源。
如果你喜欢其它语法形式的stream,你可以试一下linq.js,或者,如果你使用 node.js, node-lazy 也许更适合你。
如果你要是喜欢 CoffeeScript 的话, Michael Blume 正在把 stream.js 移植到 CoffeeScript 上,创造出 coffeestream。
感谢你的阅读!
我希望你能有所收获,并喜欢上 stream.js。这个类库是免费的,所以,如果你喜欢它,或它能在某方面提供了帮助,你可以考虑替我买一杯热巧克力饮料 (我不喝咖啡) 或者 写信给我。如果你打算这样做,请写清你是哪里人,做什么的。我很喜欢收集世界各地的图片,所以,信中请附上你在你的城市里拍的照片!
原文出处:http://www.aqee.net/docs/stream/