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

Dav*_*one 319 python functional-programming

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

Nat*_*ers 387

您引用的问题询问哪些语言促进OO和函数式编程.Python不会促进函数式编程,即使它运行得相当好.

反对 Python 函数式编程的最佳理由是Guido仔细考虑了命令式/ OO用例,而函数式编程用例则不然.当我编写命令式Python时,它是我所知道的最漂亮的语言之一.当我编写功能性Python时,它变得像你没有BDFL的普通语言那样丑陋和不愉快.

这并不是说它很糟糕,只是你必须比你改用一种促进函数式编程或转而编写OO Python的语言更加努力.

以下是我在Python中遗漏的功能性内容:


  • 没有模式匹配和没有尾递归意味着必须强制编写基本算法.递归在Python中是丑陋而缓慢的.
  • 一个小的列表库,没有功能词典意味着你必须自己写很多东西.
  • currying或composition的语法没有意味着无点样式与显式传递参数一样充满标点符号.
  • 迭代器而不是惰性列表意味着您必须知道是否需要效率或持久性,并且list如果想要持久性,则将调用分散到周围.(迭代器使用一次)
  • Python的简单命令式语法及其简单的LL1解析器意味着if-expressions和lambda表达式的更好语法基本上是不可能的.Guido喜欢这种方式,我认为他是对的.

  • 丢失尾递归的+1 - 虽然循环结构已经取代它,但它仍然值得在Python和Scheme之间缺失. (5认同)
  • 完整性和构图的完美答案.唉,就像有这么多具有​​强大功能背景的答案一样,它有IMO滥用术语.虽然我理解你无法在答案中详细说明每个概念,但我想知道在阅读诸如"模式匹配","功能词典","currying"或""之类的术语时,OP(具有允许的有限FP背景)是否是充分了解的.懒惰的名单". (5认同)
  • 我意识到这已经有5年了,但是......这似乎更像是你想念的东西_来自Haskell_,而不是来自_functional语言_.例如,大多数ML和Lisp方言和后代没有自动currying,使得无点样式过于冗长,没有惰性列表等等.因此,如果迭代器而不是惰性列表使得Python成为一种糟糕的函数式语言,那么_neither_必须使CaML成为一种功能强大的语言? (5认同)
  • 好点子; 我认为解决方案是添加链接.你有足够的代表来编辑我的答案吗?如果是这样,请随意添加各种概念的链接.我将在以后有空的时候开始. (4认同)
  • @abarnert:除了懒惰列表之外,Caml还有每个子弹点,它们可以作为库使用.我在写这个答案时偶尔使用Caml,目前使用F#.它们都是非常好的函数式语言. (4认同)
  • 只是一个注释,因为我检查了@ankostis回答:我把它看作是"cocount"是python语言的扩展这一事实.这实际上是另一种与python向后兼容并转换为python的语言.不幸的是,它不是叫cocount,而是椰子:( (2认同)

Jas*_*ker 101

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

无论人们怎么说或想到,我都从未认为Python会受到功能语言的严重影响.我更熟悉C和Algol 68等命令式语言,尽管我已经将函数设置为第一类对象,但我并未将Python视为函数式编程语言.但是,早些时候,显然用户希望使用列表和函数做更多事情.

...

值得注意的是,即使我没有将Python视为一种函数式语言,闭包的引入在许多其他高级编程特性的开发中也很有用.例如,新式类,装饰器和其他现代功能的某些方面依赖于此功能.

最后,尽管多年来已经引入了许多函数式编程特性,但Python仍然缺乏"真实"函数式编程语言中的某些特性.例如,Python不执行某些类型的优化(例如,尾递归).一般来说,由于Python具有极强的动态性,因此不可能从Haskell或ML等函数式语言中进行编译时优化.那没关系.

我从中得出两件事:

  1. 该语言的创建者并不认为Python是一种功能语言.因此,可以看到"功能性"特征,但您不太可能看到任何明确功能的东西.
  2. Python的动态特性抑制了您在其他函数语言中看到的一些优化.当然,Lisp与Python一样动态(如果不是更动态),所以这只是部分解释.

  • 我认为说Guido van Rossum不了解功能风格并且不理解为什么Python需要它们更准确.您必须了解两件事:1)编程语言位于技术堆栈的底部并影响构建在它们上的所有内容; 2)就像任何其他软件一样,添加功能比删除功能更容易.因此,对于语言设计师来说,批评这些请求是一种很好的质量. (59认同)
  • 它似乎归结为Guido van Rossum _doesn't_like_功能风格. (26认同)
  • 你可以在Python中进行尾调用优化.圭多没有/不明白. (8认同)
  • "当然,Lisp同样充满活力" - >同样必要! (8认同)
  • @Jules,你介意在Python中分享使用尾调用优化的指南吗?指向某个源的指针很有用. (6认同)

Jac*_*b B 52

Scheme没有代数数据类型或模式匹配,但它肯定是一种函数式语言.从函数式编程的角度来看,有关Python的烦人事:

  1. 残废的Lambdas.由于Lambdas只能包含表达式,并且您无法在表达式上下文中轻松完成所有操作,这意味着您可以"动态"定义的函数是有限的.

  2. 如果是陈述,而不是表达.这意味着,除其他外,你不能在里面有一个带有if的lambda.(这在Python 2.5中由三元组修复,但看起来很难看.)

  3. Guido威胁要删除地图,过滤,并每隔一段时间减少一次

另一方面,python具有词法闭包,Lambdas和列表推导(无论Guido是否承认它,它都是一个"功能性"概念).我在Python中做了很多"函数式"编程,但我很难说它是理想的.

  • @JacobB在Python发明之前大约15年以及在Python获得该功能实现之前25年,功能语言中提供了列表推导.Python已经影响了它们的传播,或者fp从Python中学到了这一点,或者甚至只是说它在Python实现后的fp世界中流行,这是完全错误的.Python的实现直接来自Haskell.也许我误解了你,这不是你的意思,但我感到困惑的是"功能人员*开始*唤醒列表理解的可怕性". (16认同)
  • @ S.Lott你如何用发电机取代减少? (13认同)
  • map和filter通常由列表推导替换.减少 - 几乎总是 - 效率低,应该用发电机功能代替. (7认同)
  • python中不需要map,filter和reduce.我还没有看到一段通过使用它们而非常简化的代码.另外,在Python中调用函数可能很昂贵,所以通常最好只使用列表/生成器理解或for循环. (3认同)
  • 这正是Nathan Sanders在下面所说的:"即使Python运行得相当好,它也不会促进功能编程." 如果Guido希望Python成为一种函数式语言,那么他将使实现工作足够好以使用一次性函数,并且将Lambdas解压缩到可以以有用的方式实际使用map/filter/reduce的程度.另一方面,功能性人员开始意识到列表理解的可怕性.希望我们不必选择其中一个. (2认同)

Kon*_*lph 22

我永远不会称Python为"功能",但每当我使用Python编程时,代码总是最终几乎完全是功能性的.

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


yai*_*chu 17

让我演示一段代码,该代码取自对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
Run Code Online (Sandbox Code Playgroud)

哈斯克尔:

grandKids generation kidsFunc val =
  iterate (concatMap kidsFunc) [val] !! generation
Run Code Online (Sandbox Code Playgroud)

这里的主要区别是,Haskell的标准库中有函数式编程有用的功能:在这种情况下iterate,concat(!!)

  • @Lloeki:迭代将显著简化代码,和(在X为v实现在kidsFunc X(V))是concatMap(kidsFunc)更清晰.与Haskell相比,Python缺乏漂亮的高阶内置函数使得等效代码更加神秘和冗长. (9认同)
  • 这里是带有生成器表达式的`grandKids()`body的单行替换:`return reduce(lambda a,v:concat((x代表kidsFunc(v)中的x)对于a中的v,x​​range(代),[ VAL])`. (7认同)
  • 而且这里也不需要`concat`:`return reduce(lambda a,v :( x代表v for a for x in kidsFunc(v)),xrange(代),[val])` (6认同)
  • concat可以由`itertools.chain.from_iterable`代替 (2认同)

小智 14

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

函数式编程就像在白板上编写数学一样.当您在白板上编写方程式时,您不会考虑执行顺序.(通常)没有突变.你不会在第二天回来看看它,当你再次进行计算时,你会得到不同的结果(或者,如果你有一些新鲜的咖啡,你也许可以:)).基本上,董事会上的内容是存在的,当你开始写下来时,答案已经存在,你还没有意识到它是什么.

函数式编程非常类似; 你不改变事物,你只需要评估等式(或者在这种情况下,"程序")并找出答案是什么.该计划仍在那里,未经修改.与数据相同.

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

此列表按我的优先顺序排列,因此参考透明度是最重要的,后面没有副作用.

现在,如果你通过python并检查语言和库如何支持和保证这些方面 - 那么你就可以回答你自己的问题了.

  • 函数在Python中是一流的。 (2认同)

S.L*_*ott 10

Python几乎是一种功能语言.它是"功能性精简版".

它有额外的功能,所以它对某些人来说不够纯粹.

它也缺少一些功能,所以对某些人来说还不够完整.

缺少的功能相对容易编写.看看像帖子对FP Python编写的.

  • -1对不起,没有.我的意思是,只是,不.功能语言提供了便于形式推理的结构:归纳(ML),等式(Haskell).闭包和匿名函数本身就是策略模式的语法糖. (8认同)
  • 在大多数情况下,我同意这篇文章.但我不同意说Python是一种功能语言.它非常鼓励命令式编程,并且很难不使用你提到的"额外功能".我认为最好将Python称为"功能性精简版",就像你在其他帖子中所做的那样.:-) (2认同)

Dvd*_*ins 8

上面没有提到的另一个原因是许多内置函数和内置类型的方法修改了一个对象但是没有返回修改后的对象.功能代码更清晰,更简洁.例如,如果some_list.append(some_object)返回了some_list并附加了some_object.


小智 5

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

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

更好的函数式语言识别这些基于数学的关系并自动执行优化。不专用于功能范式的语言可能不会优化。