我一直认为函数式编程可以在Python中完成。因此,令我感到惊讶的是,Python在这个问题上没有得到太多提及,而当提及它时,通常不是很积极。但是,没有给出太多的原因(缺少模式匹配和代数数据类型)。所以我的问题是:为什么Python对于函数式编程不是很好?除了缺乏模式匹配和代数数据类型之外,还有其他原因吗?还是这些概念对函数式编程如此重要,以致于不支持它们的语言只能被归类为一流的函数式编程语言?(请记住,我在函数式编程方面的经验非常有限。)
我一直认为函数式编程可以在Python中完成。因此,令我感到惊讶的是,Python在这个问题上没有得到太多提及,而当提及它时,通常不是很积极。但是,没有给出太多的原因(缺少模式匹配和代数数据类型)。所以我的问题是:为什么Python对于函数式编程不是很好?除了缺乏模式匹配和代数数据类型之外,还有其他原因吗?还是这些概念对函数式编程如此重要,以致于不支持它们的语言只能被归类为一流的函数式编程语言?(请记住,我在函数式编程方面的经验非常有限。)
Answers:
您所参考的问题将询问哪些语言同时促进OO和功能编程。即使Python 运作良好,它也不会促进函数式编程。
反对 Python 中的函数式编程的最佳论据是Guido仔细考虑了命令式/ OO用例,而函数式编程用例则没有。当我编写命令式Python时,它是我所知道的最漂亮的语言之一。当我编写函数式Python时,它变得和没有BDFL的普通语言一样丑陋和令人不快。
这并不是说这很糟糕,只是您必须比您改用促进功能编程的语言或改用编写OO Python的语言更加努力。
以下是我在Python中缺少的功能:
list
如果需要持久性,则需要分散调用。(迭代器只能使用一次)Guido 在这里对此有很好的解释。这是最相关的部分:
我从来没有考虑过Python受功能语言的严重影响,无论人们怎么说。我对诸如C和Algol 68之类的命令式语言更加熟悉,尽管我使函数成为一流的对象,但我并不认为Python是一种函数式编程语言。但是,很早以前,很明显,用户希望对列表和函数做更多的事情。
...
还值得注意的是,即使我没有将Python设想为一种功能语言,闭包的引入对于许多其他高级编程功能的开发也很有用。例如,新型类,装饰器和其他现代功能的某些方面都依赖此功能。
最后,尽管这些年来已经引入了许多功能编程功能,但是Python仍然缺少“真实”功能编程语言中的某些功能。例如,Python不执行某些类型的优化(例如,尾部递归)。通常,由于Python具有极强的动态特性,因此无法进行从Haskell或ML之类的功能语言中已知的那种编译时优化。很好。
我从中得出两点:
Scheme没有代数数据类型或模式匹配,但肯定是一种功能语言。从功能编程的角度来看,有关Python的烦人的事情:
残缺的Lambdas。由于Lambda仅包含一个表达式,并且您无法在表达式上下文中轻松地进行所有操作,因此这意味着您可以“即时”定义的功能受到限制。
如果是语句,而不是表达式。这意味着,除其他事项外,您不能在其中带有If的lambda。(这在Python 2.5中由三元数修复,但看起来很丑。)
圭多威胁要删除地图,过滤器,并减少在每过一段时间
另一方面,python具有词汇闭包,Lambda和列表理解(无论Guido是否接受,这实际上都是“功能性”概念)。我在Python中进行了大量的“函数式”编程,但是我很难说它是理想的。
让我用从SO上的“功能性” Python问题的答案中摘录的一段代码来演示
蟒蛇:
def grandKids(generation, kidsFunc, val):
layer = [val]
for i in xrange(generation):
layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer))
return layer
Haskell:
grandKids generation kidsFunc val =
iterate (concatMap kidsFunc) [val] !! generation
这里的主要区别是,Haskell的标准库中有函数式编程有用的功能:在这种情况下iterate
,concat
和(!!)
grandKids()
体生成器表达式:return reduce(lambda a, v: concat((x for x in kidsFunc(v)) for v in a), xrange(generation), [val])
。
concat
:return reduce(lambda a, v: (x for v in a for x in kidsFunc(v)), xrange(generation), [val])
itertools.chain.from_iterable
对于这个问题(和答案)而言,真正重要的一件事是:函数式编程到底是什么,它的最重要特性是什么。我将尽我的看法:
函数式编程很像在白板上写数学。在白板上写方程式时,您无需考虑执行顺序。(通常)没有突变。您不会在第二天回来查看它,并且当您再次进行计算时,您会得到不同的结果(或者,如果您喝了一些新鲜的咖啡,则可以:)。基本上,板子上有什么,当您开始写下内容时,答案已经在那里,您只是还没有意识到它到底是什么。
函数式编程非常像这样。您不会改变任何事情,只需评估方程式(在本例中为“程序”),然后找出答案是什么。该程序仍然存在,未经修改。与数据相同。
我将以下内容列为函数式编程的最重要特征:a)引用透明性-如果您在其他时间和地点评估相同的语句,但具有相同的变量值,则其含义仍相同。b)没有副作用-不管您凝视白板多长时间,另一个人看着另一个白板的方程式都不会意外改变。c)函数也是值。可以传递给其他变量或与其他变量一起应用。d)函数组合,您可以执行h = g·f,从而定义一个新函数h(..),该函数等效于调用g(f(..))。
此列表按我的优先顺序排列,因此参照透明性是最重要的,其次没有副作用。
现在,如果您通过python检查语言和库在这些方面的支持和保证程度,那么您就可以很好地回答自己的问题了。
Python几乎是一种功能语言。这是“功能精简版”。
它具有额外的功能,因此对于某些人来说还不够纯粹。
它还缺少一些功能,因此对于某些功能来说还不够完善。
缺少的功能相对容易编写。在Python中的FP上查看此类帖子。
除了其他答案外,Python和大多数其他多范式语言不太适合真正的函数式编程的一个原因是,因为它们的编译器/虚拟机/运行时不支持函数优化。通过编译器理解数学规则可以实现这种优化。例如,许多编程语言都支持map
函数或方法。这是一个相当标准的函数,该函数将一个函数作为一个参数,将一个Iterable作为第二个参数,然后将该函数应用于Iterable中的每个元素。
无论如何,结果map( foo() , x ) * map( foo(), y )
与相同map( foo(), x * y )
。后者的情况实际上比前者快,因为前者执行两份副本,后者执行一份。
更好的功能语言会识别这些基于数学的关系并自动执行优化。非专用于功能范例的语言可能不会进行优化。
map( foo() , x ) * map( foo(), y ) == map( foo(), x * y )
并非所有功能都正确。例如,考虑foo
计算导数的情况。
+
不是*
。