为什么Python不是很适合函数式编程呢?

我一直认为函数式编程可以用Python来完成。 因此,我很惊讶Python在这个问题上没有太多提及,当提到时,它通常不是很积极。 然而,没有多less原因给出(缺less模式匹配和代数数据types被提及)。 所以我的问题是:为什么不是Python对函数式编程非常好? 是否有比缺乏模式匹配和代数数据types更多的原因? 或者这些概念对函数式编程如此重要,以至于不支持它们的语言只能被归类为二次函数式编程语言。 (请记住,我在函数式编程方面的经验非常有限。)

您引用的问题是询问哪些语言可以同时提升面向对象和函数式编程。 即使Python运行良好,Python也不会促进函数式编程。

在Python中反对函数式编程的最好的论据是,命令/ OO用例是由Guido仔细考虑的,而函数式编程用例则不是。 当我编写命令式Python时,它是我所知道的最漂亮的语言之一。 当我编写函数式Python时,它会变得和没有BDFL的普通语言一样丑陋和不愉快。

这并不是说它不好,只是如果你改用一种促进函数式编程的语言,或者转向编写面向对象的Python,你就必须比你更努力地工作。

以下是我在Python中错过的function性的东西:

  • 模式匹配
  • 尾recursion
  • 大型的列表函数库
  • function字典类
  • 自动咖喱
  • 简洁的方式来组成function
  • 懒惰列表
  • 简单,强大的expression式语法(Python的简单块语法可以防止Guido添加它)

  • 没有模式匹配和没有尾recursion意味着你的基本algorithm必须写入命令。 recursion在Python中是丑陋而缓慢的。
  • 一个小清单库和没有function词典意味着你必须自己写很多东西。
  • 没有任何currying或组合的语法意味着无点式风格就像明确地传递参数一样充满了标点符号。
  • 迭代器而不是懒惰列表意味着你必须知道你是否想要效率或持久性,如果你想要持久化的话,把调用分散到list 。 (迭代器使用一次)
  • Python简单的命令式语法及其简单的LL1parsing器,意味着更好的if-expressions和lambdaexpression式语法基本上是不可能的。 Guido喜欢这样,我想他是对的。

圭多在这里有一个很好的解释。 这是最相关的部分:

我从来没有认为Python受到function语言的严重影响,不pipe人们怎么说或者想什么。 我对C和Algol 68等命令式语言更加熟悉,尽pipe我已经将函数作为一stream的对象,但我并没有把Python看作一种function性的编程语言。 不过,早些时候,很明显,用户想要做更多的清单和function。

值得注意的是,尽pipe我没有将Python视为一种function性语言,但是闭包的引入对于许多其他高级编程function的开发非常有用。 例如,新风格类,装饰器和其他现代特征的某些方面依赖于这种能力。

最后,尽pipe多年来引入了许多function性编程function,但Python仍然缺乏“真实”function编程语言中的某些function。 例如,Python不执行某些种类的优化(例如,尾recursion)。 一般来说,因为Python非常dynamic的性质,所以不可能从Haskell或ML等函数语言中进行那种编译时优化。 这很好。

我从这件事中拉出两件事:

  1. 该语言的创build者并不认为Python是一种function性语言。 因此,有可能看到“function性”的function,但是你不可能看到任何明确的function。
  2. Python的dynamic特性抑制了你在其他函数式语言中看到的一些优化。 当然,Lisp和Python一样dynamic(如果不是更dynamic的话),所以这只是一个部分的解释。

Scheme没有代数数据types或模式匹配,但它当然是一种function语言。 从function编程的angular度来看,讨厌Python的一些事情:

  1. 残废的兰姆达斯。 由于Lambdas只能包含一个expression式,并且在expression式上下文中不能做任何事情,所以这意味着您可以“即时”定义的函数是有限的。

  2. 如果是语句,则不是expression式。 这意味着,除了别的以外,你不能在里面有一个带有If的lambda。 (这是由Python 2.5中的三元组修复的,但看起来很难看。)

  3. Guido威胁要删除地图,filter,并在一段时间内减less

另一方面,python有词法closures,Lambdas和列表parsing(无论Guido是否承认它,这实际上是一个“function”概念)。 我在Python中做了大量的“函数式”编程,但是我很less说这是理想的。

我永远不会调用Python“function”,但每当我用Python编程的代码总是最终几乎是纯粹的function。

无可否认,这主要是由于非常好的列表理解。 所以我不一定build议Python作为函数式编程语言,但是我会build议使用Python的人使用函数式编程。

让我来演示一个从SO上“function性” Python问题的答案中获取的代码

python:

 def grandKids(generation, kidsFunc, val): layer = [val] for i in xrange(generation): layer = itertools.chain.from_iterable(itertools.imap(kidsFunc, layer)) return layer 

哈斯克尔:

 grandKids generation kidsFunc val = iterate (concatMap kidsFunc) [val] !! generation 

这里的主要区别在于Haskell的标准库对函数式编程有用,在这种情况下, iterateconcat(!!)

Python几乎是一种function性语言。 这是“function简洁”。

它有额外的function,所以它不够纯粹的一些。

它也缺乏一些function,所以对某些function还不够完善。

缺less的function相对容易编写。 在Python中查看FP上的post。

有一件事对于这个问题(以及答案)是非常重要的,那就是:函数式编程到底是什么,它最重要的属性是什么。 我会尝试给我的看法:

函数式编程就像在白板上写math一样。 当您在白板上书写方程时,您不会考虑执行顺序。 (通常)没有突变。 你一天不会回来看看,当你再次进行计算时,你会得到不同的结果(或者,如果你有一些新鲜的咖啡:))。 基本上,董事会里有什么东西,当你开始写下来的时候,答案已经在那里了,你还没有意识到它到底是什么。

函数式编程就是这样的; 你不改变事情,你只是评估方程(或在这种情况下,“程序”),并找出答案是什么。 该程序仍然存在,未经修改。 与数据一样。

我将以下列为函数式编程的最重要特征:a)参照透明度 – 如果您在其他时间和地点评估相同的语句,但具有相同的variables值,它仍然意味着相同。 b)无副作用 – 不pipe你盯着白板多久,另一个人在另一个白板上看的等式不会意外地改变。 c)function也是值。 可以传递给其他variables并应用于其他variables。 d)函数组合,你可以做h = g·f,从而定义一个新的函数h(..),它相当于调用g(f(..))。

这份清单是按照我的优先顺序排列的,所以参考透明度是最重要的,其次是没有副作用。

现在,如果你通过Python来检查语言和图书馆对这些方面的支持和保证,那么你就可以很好地回答你自己的问题了。

上面没有提到的另一个原因是许多内置types的内置函数和方法修改对象,但不返回修改的对象。 例如,如果some_list.append(some_object)返回了some_list并附加了some_object,那么function代码就会更清晰更简洁。

除了其他答案之外,Python和大多数其他多范式语言不适合真正的函数式编程的原因之一,是因为它们的编译器/虚拟机/运行时不支持function优化。 这种优化是通过编译器理解math规则来实现的。 例如,许多编程语言都支持map函数或方法。 这是一个相当标准的函数,它将一个函数作为一个参数,将一个可迭代的函数作为第二个参数,然后将该函数应用于迭代器中的每个元素。

无论如何,事实certificatemap( foo() , x ) * map( foo(), y )map( foo(), x * y ) 。 后一种情况实际上比前者快,因为前者执行两个副本,后者执行一个副本。

更好的function语言可以识别这些基于math的关系并自动执行优化。 不专用于function范例的语言可能不会优化。