在惰性求值中,我们引入了“惰性列表”的概念。这个概念实际上在Python中有一些原生支持。这就是生成器和迭代器让新手感到困惑的地方。但在此之前,我们首先需要回顾一下列表的功能。从二进制元组到列表首先,我们可以使用\(\lambda\)演算来定义一个二进制元组,或对:pair:\(\lambdaabf.fab\)first:\(\lambdap.p(\lambdaab.a)\)second:\(\lambdap.p(\lambdaab.b)\)具体实现如下:pair=lambdaa:lambdab:lambdaf:f(a)(b)first=lambdap:p(lambdaa:lambdab:a)second=lambdap:p(lambdaa:lambdab:b)我们可以定义测试:>>>p=pair(1)(2)>>>first(p)1>>>second(p)2当然有了pair,定义一个list也不难,就是下面的组合就可以了(我们还是用python自带的tuple):(1,(2,3,(4,()))))我们将在后面的章节中使用元组和类/类型来定义列表。但是这篇文章,让我们回到之前python的概念,看看函数式编程是如何处理遍历问题的。列表操作列表操作是函数式编程的一个重要概念。实时地,它使用递归来遍历一个线性结果。例如,下面的C风格代码:ls=[1,2,3,4]foriinrange(0,len(ls)):ls[i]=ls[i]+1有两个副作用这里,一个是i的自增,一个是ls的就地运算。此外,他们还使用变量的概念。当然,这样的写法并没有什么问题,而且可维护性尚可,也算是可以忍受的副作用。当然,我们最简单的实现相当于大家都知道它是一个列表表达式(当然,其实它还是有副作用的):[i+1foriinls]当然大部分人也看过完整的列表表达式操作,可以自带过滤器:[i+1forininlsifi%2==0]这是函数式编程遍历数据最简单的操作。当然,它们还有一个名字,就是map和filter。在Python中,它们返回可迭代对象(我们可以调用列表来转换为列表):map(lambdax:x+1,ls)#[i+1foriinls]filter(lambdax:x%2==0,ls)#[iforiinlsifx%2==0]另一个常用的列表操作是reduce,起到聚合作用。我们只需要定义一个二元操作来合并列表,从头开始进行End-to-end聚合操作。reduce操作视图解决的问题是遍历后汇总值的过程。比如我们要实现ls的求和,在一般的过程式编程中,我们会使用如下方法:res=0foriinls:res+=i#或者更类似的写法res=res+iand,使用reduce,我们只需要下面的代码就可以完成。fromfunctoolsimportreducereduce(lambdax:x+y,ls)具体计算过程如下:得到ls的第一个值1和第二个值2,应用lambdax,y:x+y,得到3。ls的第三个值3,应用第一步的结果3和lambda得到6。得到ls的第三个值4,应用第二步的结果6和lambda得到10,计算后返回结果。然而,实际上,如果我们查看Python的reduce函数的参数,就会发现它也可以带入初始值。带初值的时候一般在各种函数语句中调用fold_left/foldl函数。有没有初始值,效果会有很大的不同。第一个是处理list为空的问题:reduce(lambdax,y:x+y,[])#报错reduce(lambdax,y:x+y,[],0)#return0我们甚至可以把这个对应到前面程序化编程的各个元素。0相当于res=0,lambdax,y:x+y表示res=res+i。然而,事实上,foldl比reduce更强大的地方在于操作本身可以涉及不同的类型。当我们使用typeflag时,会发现reduce函数本身的操作只能是Callable[[S,S],S]/(S,S)->S,但实际上在很多场景下,what我们需要的是类型加载Change。例如:[1,2,3,4]=>"1234"[1,2,3,4]=>[[1],[2],[3],[4]]...如果你简单的说我们不能在reduce中操作涉及类型转换的内容,而foldl带来的二元操作类型注解是Callable[[S,T],S]/(S,T)->S。这让我们可以通过设置另一种类型的初始值,比如上面转换为字符串的例子,我们很容易发现如下二元操作(注意顺序):lambdax,y:x+str(y)而初始值只需要设置一个空的""字符串,即下面的实现(尝试实现[1,2,3,4]=>[[1],[2],[3],[4]]!):reduce(lambdax,y:x+str(y),ls,"")总结在这篇文章中,我们回顾了Python原生的列表并介绍了函数公式编程使用列表表达式/列表操作来实现过程式编程中常见的数据遍历问题,以避免for/while中不可避免的副作用。接下来我们将使用pair的概念从零开始实现一个list,然后进入正式的lazylist的概念,看看lazylist是如何处理这类问题的,从函数的角度去思考流处理和线程的概念.
