当前位置: 首页 > 后端技术 > Python

Python函数式编程系列010:为惰性列表实现List

时间:2023-03-25 23:50:47 Python

在这篇文章中,我们将手工实现一个List,但与普通文章不同的是,我们这里没有使用类来实现,而是使用基本的数据结构。元组(a,b)和空元组()实现。这两个都可以直接通过lambda来定义。具体方法可以参考上一篇文章。大家想一想,List(也叫链表),最重要的是创建一个可以无限扩展自身的模式,保存一个值和下一个数据,比如[1,2,3,4]我们可以用(1,(2,(3,(4,()))))。我们必须指定一个结束,这就是()在其中的作用,()代表空列表和列表结束的意思。很简单,我们可以这样定义列表(我在这里包含了一个函数,只是为了隔离数据,防止我们使用内置的比较来实现一些功能):defcons(head,tail):defhelper():return(head,tail)returnhelper然后我们定义两个函数来获取里面的数据,类似于前面接口中的first和second:head=lambdacons_list:cons_list()[0]tail=lambdacons_list:cons_list()[1]我们可以定义一个函数来表示空变量empty_list_base。之后为了计算方便,我们可以写一个方便的方法来生成cons(当然这个实现使用了*arg的概念,我们默认使用这个语法糖特性):defcons_apply(*args):iflen(args)==0:returnempty_list_baseelse:returncons(args[0],cons_apply(*args[1:]))这样我们就可以轻松完成新的List:>>>cons_apply(1,2,3)#returncons(1,cos(2,cos(3,())))为了比较方便,我们也可以定义一个判断列表是否相等的函数:defequal_cons(this:ListBase[S],that:)->bool:如果this==empty_list_baseandthat!=empty_list_base:returnFalseelifthis!=empty_list_baseandthat==empty_list_base:returnFalseelifthis==empty_list_baseandthat==empty_list_base:returnTrueelse:returnhead(this)==head(that)和equal_cons(tail(this),tail(that))现在我们可以轻松地做一些验证>>>assertequal_cons(cons_apply(1,2,3),cons(1,cons(2,cons(3,()))))现在我们需要的是实现一些不需要循环实现的列表操作,也就是上一篇文章中提到的map、fold_left和filter。map的作用是将函数f带入list的每一个值,也就是我们把f带入list的头部之后,再将map应用到尾部,即:defmap_cons(f,cons_list):ifcons_list==():returnempty_list_baseelse:returncons(f(head(cons_list)),map_cons(f,tail(cons_list)))同样,我们可以实现filter和fold_left:deffilter_cons(f,cons_list):如果cons_list==():returnempty_list_baseelse:hd,tl=head(cons_list),tail(cons_list)如果f(hd):returncons(hd,filter_cons(f,tl))else:returntldeffold_left_cons(f,init,cons_list):ifcons_list==():returninitelse:returnfold_left_cons(f,f(init,head(cons_list)),tail(cons_list))这样我们就可以实现一些基本的功能,比如[1,2,3,4,5]每个元素加一,过滤偶数求和,可以写为:>>>res=fold_left_cons(lambdax,y:x+y,0,>>>filter_cons(lambdax:x%2==0,>>>map_cons(lambdax:x+1,>>>cons_apply(1,2,3,4,5)>>>)))>>>res==12当然,这种风格的代码,嵌套可读性差,这里我我们想到了之前实现的and_then或者compose函数,可以把这些水管构造出来的东西组合起来。不过,如果我们把这些函数改成curry,写起来会更方便。这允许函数组合样式:map_cons_curry=lambdaf:lambdacons_list:map_cons(f,cons_list)filter_cons_curry=lambdaf:lambdacons_list:filter_cons(f,cons_list)fold_left_cons_curry=lambdaf:lambdainit:lambdafoldcons_le_list:(f,init,cons_list)具体调用如下方法:>>>f=and_then(>>>map_cons_curry(lambdax:x+1),>>>filter_cons_curry(lambdax:x%2==0),>>>fold_left_cons_curry(lambdax,y:x+y)(0),>>>)>>>>>>assertf(cons_apply(1,2,3,4,5))==12如果你使用fppy实例(点此进入)我维护,你也可以用一个F_修饰轮,这样你就可以实现另一种基于类的链式写法:fromfppy.baseimportF_,IF_(I)\.and_then(map_cons_curry(lambdax:x+1))\.and_then(filter_cons_curry(lambdax:x%2==0))\.and_then(fold_left_cons_curry(lambdax,y:x+y)(0))\.apply(cons_apply(1,2,3,4,5))#return12在本文中,我们简单的使用了二元组的概念,equality,和函数来维护一个结果列表,并且可以通过一些列表函数的对齐来进行遍历计算和筛选。在下一篇文章中,我们将开始粗略地讨论类和类型的概念,这将有助于我们以后的讨论。