我一直认为函数式编程可以用Python完成。因此,我很惊讶Python在这问题中没有得到太多的提及,而且当它被提及时,通常不是非常积极的。然而,没有给出太多原因(缺乏模式匹配和代数数据类型被提到)。所以我的问题是:为什么Python不适合函数式编程?除了缺乏模式匹配和代数数据类型之外,还有其他原因吗?或者这些概念对函数式编程如此重要,以至于不支持它们的语言只能被归类为二流函数式编程语言?(请记住,我在函数式编程方面的经验相当有限。)
Guido对这个在这里有一个很好的解释。以下是最相关的部分:
我从来不认为Python是 很大程度上受功能性的影响 语言,不管人们说什么 或者思考。我要熟悉得多 使用命令式语言,如C 和Algol 68,虽然我做了 函数类对象,I 不认为Python是函数式的 编程语言。然而,早些时候 很明显,用户想这样做 ... 值得注意的是,即使 虽然我并没有把Python想象成 函数式语言,介绍 的闭包在 其他许多先进的开发 编程功能。例如, 新式课程的某些方面, 装饰,和其他现代功能 . 最后,尽管一些 函数式编程特性具有 已经被介绍过了,Python 仍然缺乏某些特征发现 “真正的”函数式编程 语言。例如,Python就是这样 不执行某些种类的 优化(例如,尾部递归)。 一般来说,因为Python非常 动态自然,是不可能做到的 编译时优化 众所周知的函数式语言 Haskell或ML。这很好。
...
最后,尽管一些 函数式编程特性具有 已经被介绍过了,Python 仍然缺乏某些特征发现 “真正的”函数式编程 语言。例如,Python就是这样 不执行某些种类的 优化(例如,尾部递归)。 一般来说,因为Python非常 动态自然,是不可能做到的 编译时优化 众所周知的函数式语言 Haskell或ML。这很好。
我从中得出两点结论:
Python几乎是一种函数式语言。它是“功能精简版”。
它有额外的特性,所以对某些人来说不够纯。
它还缺乏一些功能,因此对某些人来说还不够完整。
缺少的特性相对容易编写。查看类似这的关于Python中的FP的帖子。
Scheme没有代数数据类型或模式匹配,但它肯定是一种函数式语言。从函数式编程的角度来看,Python令人讨厌的地方:
λ。由于Lambdas只能包含一个表达式,并且不能在表达式上下文中轻松地做所有事情,这意味着可以“动态”定义的函数是有限的。
if是语句,不是表达式。这意味着,除其他外,你不能有一个包含If的lambda。(这在Python 2.5中由三元组修复,但看起来很难看。)
Guido威胁删除映射,过滤器和减少每隔一段时间
另一方面,python有词法闭包、Lambdas和列表推导式(无论Guido是否承认,这实际上是一个“函数式”概念)。我用Python做了很多“函数式”编程,但我不敢说它是理想的。
您引用的问题是哪些语言同时促进面向对象和函数式编程。Python没有促进函数式编程,尽管它作品相当好。
Python中反对函数式编程的最佳论据是Guido仔细考虑了命令式/OO用例,而函数式编程用例则不是。当我编写命令式Python时,它是我所知道的最漂亮的语言之一。当我编写函数式Python时,它变得像没有BDFL的普通语言一样丑陋和令人不快。
这并不是说它不好,只是说您必须比转换到促进函数式编程的语言或转换到编写OO Python时更加努力。
以下是我在Python中遗漏的函数性内容:
list
我从来不会称Python为“函数式”,但无论何时我用Python编程,代码总是几乎完全是函数式的。
不可否认,这主要是由于非常好的列表理解。所以我不一定建议Python作为函数式编程语言,但我建议使用Python的人进行函数式编程。
让我用一段代码来演示,这段代码取自SO上的“功能性”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
Haskell:
grandKids generation kidsFunc val = iterate (concatMap kidsFunc) [val] !! generation
这里的主要区别是Haskell的标准库有用于函数式编程的有用函数:在本例中是iterate、concat和(!!)
iterate
concat
(!!)
除了其他答案之外,Python和大多数其他多范式语言不适合真正的函数式编程的一个原因是,它们的编译器/虚拟机/运行时不支持函数式优化。这种类型的优化是通过编译器理解数学规则来实现的。例如,许多编程语言都支持map函数或方法。这是一个相当标准的函数,它将一个函数作为一个参数,一个可迭代对象作为第二个参数,然后将该函数应用于可迭代对象中的每个元素。
map
不管怎样,map( foo() , x ) * map( foo(), y )和map( foo(), x * y )是一样的。后者实际上比前者快,因为前者执行两个副本,而后者执行一个副本。
map( foo() , x ) * map( foo(), y )
map( foo(), x * y )
更好的函数式语言能够识别这些基于数学的关系,并自动执行优化。不致力于函数式范式的语言可能无法优化。
上面没有提到的另一个原因是,许多内置类型的内置函数和方法修改了对象,但不返回修改后的对象。如果返回这些修改后的对象,将使函数代码更干净、更简洁。例如,如果some_list.append(some_object)返回附加some_object的some_list。