用python实现函数式编程缺少的特性

fn的Python项目详细描述


fn.py:在python中享受fp
=============


尽管python不是纯函数式编程语言,但它是多范式的pl语言,它给了您足够的自由,可以从函数式编程方法中获得
的学分。函数式有理论和实践上的优势:

-形式可证明性
-模块性
-可组合性
-易于调试和测试

``fn.py``库为您提供缺少的"电池",即使在主要是命令式程序。

My Pycon UA 2012 Talks中有关函数式方法的更多信息:`Functional
代码块::python

from fn import
from fn.op import zipWith
from itertools import repeat


assert list(map(*2,range(5))==[0,2,4,6,8]
assert list(filter(lt;10,[9,10,11])==[9]
assert list(zipWith(+u)(0,1,2),repeat(10)))==[10,11,12]

**如果您在交互式python shell中工作,您应该记住,````表示"最新输出",您将得到不可预测的结果。在这种情况下,可以执行类似"from fn import"的操作(然后编写类似"x*2"的函数)。

代码块::python


这是另一个确保您正确执行所有操作的限制:

…代码块::python

>>from fn import(1)
traceback(最近一次调用的最后一次):
file"<;stdin>;",第1行,in<;module>;
file"fn/underline.py",第82行,in"uu call"
raise arityerro(self,self.&u arity,len(args))
fn.underline.arityerror:(+u)需要2个参数,得到1




persistent data structures
-

**注意:*persistent data structures正在积极开发中。

persistent data structure是一种数据结构,always在修改之前的版本时会保留它自己(关于"wikipedia<;http://goo.gl/8vveoh>;"的更正式信息)。使用这种数据结构的每个操作都会生成一个新的更新结构,而不是就地修改(所有以前的版本都可能提供,或者在可能的情况下进行gc-ed)。

代码块::python

>;>;来自fn.immutable import skewheap
>;>;s1=skewheap(10)
>;>;s2=s1.insert(20)
>;>;s2
<;fn.immutable.heap.skewheap object at 0x10b14c050>;
>;s3=s2.insert(30)
>;>;>;s3
<;fn.immutable.heap.skewheap object at 0x10b14c158>;<;--其他对象
>;>;s3.extract()
(10,<;fn.immutable.heap.skewheap object at 0x10b14c050>;)
>;s3.extract()<;--s3未更改
(10,<;fn.immutable.heap.skewheap object at 0x10b11c052>;)

放松,深呼吸,阅读一些使持久数据结构快速高效的技术:`structural sharing<;http://en.wikipedia.org/wiki/persistent戋data戋structure戋examples戋of戋persis帐篷数据结构和路径复制http://en.wikipedia.org/wiki/persistent数据结构和路径复制可以查看Zach Allaun's Talk(Strangeloop 2013):"函数向量、映射和集合在Julia中"的幻灯片。.gl/cp1qsq>;`.

,如果你足够勇敢,请阅读:

-chris okasaki,"纯功能数据结构"(`amazon<;http://goo.gl/c7ptkk>;` `)
-fethi rabhi和guy lapalme,"算法:功能编程方法"(`amazon<;http://goo.gl/00bxto>;` `)

``fn.immutable``模块中可用的不可变数据结构:

-``linked list``:最"明显"的持久数据结构,用作其他基于列表的结构(堆栈、队列)的构建基块
-``stack``:使用知名的pop/push api包装链表实现
-``queue``:使用两个链表和惰性复制提供o(1)排队和出列操作
-``deque``(正在进行):`"通过数据合并持久的deques
结构引导"<;http://goo.gl/vvtzx3>;``\br/>-``deque``基于``fingertree``数据结构(请参阅更多信息在下面)
-``vector`:o(log32(n))通过索引访问元素(对于合理的向量大小来说接近-o(1)),实现基于``bitmappedtrie``,几乎是内置python``list``的替换项
-``skewheap``:自调整堆实现为具有指定ic分支模型,使用堆合并作为基本操作,更多信息-`"自调整堆"<;http://goo.gl/r1pzme>;`
-` ` pairing heap`:`"配对堆:自调整堆的新形式"<;http://goo.gl/aivtph>;`
-` ` dict`(进行中):持久散列映射实现基于"bitmappedtrie`
-``fingertree``(正在进行):`"finger trees:一个简单的通用数据结构"<;http://goo.gl/bzo0df>;` ` ` ` `

使用适当的文档字符串获取有关每个数据结构的更多信息以及示例代码。

以获得更清晰的Vision关于持久堆是如何工作的("skewheap"和"pairingheap"),您可以看我的演讲"基于联合的堆"中的幻灯片<;http://goo.gl/vmgdg2>;`(使用python和haskell中的分析数据结构定义)。

**注意。**大多数函数式语言使用持久数据结构a最基本的构建块,著名的例子是clojure、haskell和scala。clojure社区致力于推广基于数据不变性思想的编程。rich hickey(clojure的创建者)给出了一些令人惊叹的谈话,您可以检查它们以找到关于"如何"这两个问题的答案。"为什么?":

-`"值的值"<;http://goo.gl/137ug5>;` ` ` `
-`"持久数据结构和托管引用"<;http://goo.gl/m3vz7e>;` `

流和无限序列声明.基本思想:评估每个新的
元素"按需",并在所有创建的
迭代器之间共享计算的元素。`` stream``对象支持`<;``运算符,这意味着在必要时推送
新元素。


最简单的情况:

……从fn-import stream


>s=stream()<;[1,2,3,3,3,4,5]
assert list(s)=[1,2,3,3,4,5]
assert s[1]==2
assert list(s[0:2])==[1,2]





assert list(s)assert list(s===[1,2,4,5个,6,7]


def gen():
yield 1
yield 2
yield 3

assert list===[1,2,3,4,5]


lazy evaluated stream对于无限序列是有用的,即fibonacci
序列可以计算为:
from fn import stream
from fn.iters import take,drop,map
from operat或者导入add


>f=stream()
>fib=f<;[0,1]<;map(add,f,drop(1,f))



assert list(take(10,fib))===[0,1,1,2,3,5,8,13,13,21,34]
assert fib[20]==6765
assert list(fib[30:35])====[832042040134414141414146362042042041346269221783078309330935245784557785778572887]



>蹦床床装潢蹦床装饰装修或n.recur.tco``是一种在没有大量堆栈利用率的情况下处理tco的解决方案。让我们从递归阶乘计算的简单示例开始:

…代码块::python

def fact(n):
如果n==0:return 1
return n*fact(n-1)

为什么?它将利用内存太重的原因递归存储所有以前的值来计算最终结果。如果要用大的"n"执行此函数(大于"sys.getRecursionLimit()"),cpython将失败,

。代码块::python

>;>import sys
>;>fact(sys.getRecursionLimit()*2)
…stacktrace的许多行…
运行时错误:超过了最大递归深度

这很好,因为它可以防止代码中出现严重错误。

我们如何优化此解决方案?答案很简单,让转换函数使用尾部调用:

…代码块::python

def fact(n,acc=1):
如果n==0:return acc
return fact(n-1,acc*n)

因为你不需要记住以前的值来计算最终结果。关于wikipedia上的"tail call optimization"的更多信息,请访问http://en.wikipedia.org/wiki/tail-call>;`。但是…python解释器将以与前一个相同的方式执行此函数,因此您不会赢得任何结果。

``fn.recur.tco``为您提供了编写"优化了一点"尾调用递归的机制(使用"蹦床"方法):

。代码块::python


@recur.tco
def fact(n,acc=1):
如果n==0:return false,acc
return true,(n-1,acc*n)

``@recur.tco``是一个decorator,它在`` while`循环中执行您的函数并检查输出:

-``(false,result)``意味着我们完成了
-``(true,args,kwargs)``意味着我们需要用其他参数重新调用函数
-``(func,args,kwargs)``来切换要在while循环中执行的函数

当需要在求值循环中切换可调用时,最后一个变量非常有用。这种情况的一个很好的例子是递归检测,如果给定的数字是奇数或偶数:

…代码块::python

>;>;来自fn import recur
>;@recur.tco
…偶数定义(x):
…如果x==0:返回false,true
…奇数返回(x-1,)

>>gt;@recurr.tco
…奇数定义(x):
…如果x==0:返回false,false
…平均回报(x-1,)

>;>print even(100000)
true

**注意:**小心可变/不可变的数据结构处理。

---------

``fn.uniform``为您提供"统一"
一些函数的惰性功能,以便在python中以相同的方式工作
2+/3+:

-`map``(返回python 2中的"itertools.imap"+)
-``filter``(返回python 2中的"itertools.ifilter`+)
-``reduce``(返回python 3中的"functools.reduce`+)
-``zip`(返回python 2中的"itertools.izip`+)
-``range`(返回python 2中的"xrange`+)
-``filterfalse``(返回python 2+中的"itertools.ifilterfalse`+)
-``ZIP` longest``(在Python2+中返回``itertools.izip` longest````````+
-``accumulate``(后端口到Python<;3.3)

``fn.iters``是使用迭代器的高级配方。其中大部分来自"python
docs<;http://docs.python.org/2.7/library/itertools.html itertools.product>;``并采用它与python 2+/3+一起工作。像``drop``、
``takelast`、``droplast`、``splitat`、``splitby``这样的菜谱,我已经
以` docs patch<;http://bugs.python.org/issue16774>;``的形式提交了,现在是
审阅状态。

-``take`、``drop`
-``takelast`、``droplast`
-`` head`(别名:'````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````````
-``分区````splitat``,``splitby``
-``flatten`
-``iter`,除了`

yev/fn.py/blob/master/tests.py>;` `.


代码块::python

from fn import f,
from operator import add,mul

与functools.partial相同,但返回fn.f instance
assert f(add,1)(10)==11

f<;<;f表示函数组合,,
so(f(f)<;g(x)==f(g(x))
f=f(add,1)<;f(mul,100)
assert list(map(f,[0,1,1,2])===[1,101,201]
assert list(map(f()<;str<;<;str<;([2]<;<;<;<;<;<;(+1),range(3))==[[1","1","4","9"]==[[[1","4","4","9"]]

br/>f=f(add 1,1)<;f(mul 100)可读性强用于处理函数组合的cases"pipe"符号:

…代码块::python

from fn import f,
from fn.iters import filter,range

func=f()>;;(filter,lt;6)>;>;sum
assert func(range(10))==15

/>code<;https://github.com/kachayev/fn.py/blob/master/fn/underline.py>;` ` `.

` ` ` `fn.op.apply``使用列表(或任何其他iterable)中给定的位置参数执行给定的函数。`` fn.op.flip``返回函数
,该函数将在应用前反转参数顺序。

…代码块::python

from fn.op import apply,flip
from operator import add,sub

assert apply(add,[1,2])==3
assert flip(sub)(20,10)=-10
assert list(map(apply,[add,mul],(1,2),(10,20))==[3200]

``fn.op.foldl``和``fn.op.foldl`r``是折叠运算符。每个函数都接受arity为2的函数,并返回可用于减少iterable to scalar的函数:对于"foldl"和"foldr",分别从左到右和从右到左。

…代码块::python


from fn import op,

assert 6==op.foldl(+1;([1,2,3])
assert 6==folder([1,2,3])


右侧折叠的特定用例是:

代码块::python


from fn.op import foldr,call

assert 400==foldr(call,10)(lambda s:s**2,lambda k:k+10])



``是用于生成当前函数的装饰器,例如:

…代码块::python

>;>;来自fn.func import curried
>;@curried
…def sum5(A、B、C、D、E):
…返回a+b+c+d+e

>;>sum5(1)(2)(3)(4)(5)
15
>;>sum5(1,2,3)(4,5)
15




——

``fn.monad.option``表示可选值,``option``的每个实例可以是``full``的实例,也可以是``empty``的实例。它提供了一种简单的方法来编写长的计算序列,并去掉许多"if/else"块。参见下面的用法示例。

假设有一个"request"类,该类按名称为参数值提供值。要获取非空条带化值的大写表示法:

…代码块::python

class request(dict):
def参数(self,name):
return self.get(name,none)

r=request(testing="fixed",empty=)
param=r.parameter("testing")
如果param为none:
fixed=
else:
param=param.strip()
如果len(param)==0:
fixed=
否则:
fixed=param.upper()



用"fn.monad.option"更新代码:

…代码块::python

from operator import methodcaller
from fn.monad import optionable


类请求(dict):
@optionable
def参数(self,name):
return self.get(name,none)

r=请求(testing="fixed",empty=""
fixed=r.parameter("testing")
.map(methodcaller("strip"))
.filter(len)
.map(methodcaller("upper"))
.get或(")

``fn.monad.option.or\u call``是尝试多个变量到结束计算的好方法。也就是说,use have ``request``类具有可选属性``type``,``mimetype`,``url``。您需要使用至少一个属性来评估"请求类型":

…代码块::python

from fn.monad import option

tp=option\
。from_value(request.get("type",none))\;首先检查"type"键
。或者调用(from_mimetype,request)\。检查"mimetype"键
。或呼叫(从分机,请求)或…获取"url"并检查扩展名
。获取或("应用程序/未定义的")



代码块::console

$pip install fn

代码块:console

$easy_install fn

代码块:console

$git clone https://github.com/kachayev/fn.py.git
$cd fn.py
$python setup.py install


work-in-progress
-------

"路线图":

-``fn.monad.s

要考虑的想法:

-scala样式的yield循环,以简化长映射/筛选块


有助于
——


1。检查是否有未解决的问题,或打开新问题,围绕功能理念或缺陷展开讨论。
2。分叉github上的存储库,开始对
主分支(或其分支)进行更改。
3。编写一个测试,显示错误已修复或功能
按预期工作。

2013年3月31日,添加了"fn.stream"的初始原点参数ITH changing callable


16.02.2013
--


-fixed@23 about flipping of underline function
-added special uniform module
-fixed@22(underline functions representation)
-调整一元运算符pro下划线处理

02.02.2013
--


-处理递归函数的"recurr.tco"的初步实现
-``iters.flatten``被重新实现以处理不同的迭代器


27.01.2013
--

-``iters.accumulate`-python的后端口版本<;3.3
-第一个实现带有测试和自述示例的"monad.option"的选项


23.01.2013
----

-``fn.stream``切片是另一个"fn.stream``
-``fn.stream``获得新的公共方法``cursor``以获取下一个计算元素的位置

21.01.2013
----

-使用特殊的"fn"更新文档切实可行的炮弹
-将"zipWith``zipWith``从``fn.iters``转移到``fn.op````fn ```fn.iters``到``fn.iters`````fn.iters````fn.op``
->
>
>
-2013年1月17日将22个itertools食谱添加到``fn.iters`````fn.iters````fn.iters``到``fn.iters``````fn.op````fn.op````````fn.op``````fn.op`br/>-```流迭代器``在python 2/3中都可以正常工作

16.01.2013
----


-完成下划线模块功能
-所有已实现模块/功能的测试用例
-在readme文件中进行更新,并进行了一些修复
-在pref中去掉f.flip classmethod。对于简单的构建块
-fn.op.flip oper的优化版本
<2013年1月14日

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java无法获得正确的温度转换输出   java如何使用vlcj版本4.7.0制作用于音频流的HeadlesMediaPlayer?   java密钥斗篷无法获取访问令牌   java Uribacon的BeaconLayout是什么?   mysql的java Spring数据xml配置   java从使用布局的页面适配器中删除特定位置页面。刷卡   java使用安卓从web目录读取文件   java使用Sikuli导出应用程序   swing JAVA如何更新已绘制的字符串?   java Worker任务在WildFly中多次生成   爪哇12小时制(上午/下午)   java生成Google地图发布密钥   java如何在IntelliJ中将maven模块的groupId添加到名称/表示中   java Selenium WebDriver标识输入标记内的Td value元素   java如何将JAXWS中的Date@webgram映射到xsd:Date而不是xsd:datetime?   java Remove arraylist字符串停止随机函数   java使用googlehttpclientxml解析xml:使用XmlObjectParser解析xml元素内容和属性   java如何在array response 2中获取特定的响应数据   java我无法为安卓导入或使用AdView