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

Why isn't Python very good for functional programming?

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


您所参考的问题询问哪些语言同时促进OO和函数式编程。虽然Python工作得相当好,但它并不促进函数式编程。

在python中,反对函数式编程的最佳论据是guido会仔细考虑命令式/oo用例,而函数式编程用例则不会。当我编写命令式Python时,它是我所知道的最漂亮的语言之一。当我编写功能性的Python时,它会变得和一般没有bdfl的语言一样丑陋和令人不快。

这并不是说这很糟糕,只是如果你切换到一种促进函数式编程的语言,或者切换到编写oo python的语言,你必须比以前更加努力地工作。

以下是我在python中错过的功能:

  • 模式匹配
  • 尾部递归
  • 大型列表函数库
  • 函数字典类
  • 自动电流
  • 简洁的函数组合方式
  • 懒惰列表
  • 简单、强大的表达式语法(python的简单块语法阻止guido添加它)
  • 没有模式匹配和尾部递归意味着必须强制编写基本算法。在Python中,递归是丑陋且缓慢的。
  • 一个小的列表库和没有功能字典意味着你必须自己写很多东西。
  • 没有任何句法可以表示无点样式和显式传递参数一样充满标点符号。
  • 迭代器而不是懒惰的列表意味着你必须知道你想要效率还是持久性,如果你想要持久性的话,还必须分散对list的调用。(迭代器使用一次)
  • python的简单命令语法和它的简单ll1语法分析器意味着,基本上不可能为if表达式和lambda表达式提供更好的语法。吉多喜欢这样,我认为他是对的。


吉多对此有很好的解释。以下是最相关的部分:

I have never considered Python to be
heavily influenced by functional
languages, no matter what people say
or think. I was much more familiar
with imperative languages such as C
and Algol 68 and although I had made
functions first-class objects, I
didn't view Python as a functional
programming language. However, earlier
on, it was clear that users wanted to
do much more with lists and functions.

...

It is also worth noting that even
though I didn't envision Python as a
functional language, the introduction
of closures has been useful in the
development of many other advanced
programming features. For example,
certain aspects of new-style classes,
decorators, and other modern features
rely upon this capability.

Lastly, even though a number of
functional programming features have
been introduced over the years, Python
still lacks certain features found in
"real" functional programming
languages. For instance, Python does
not perform certain kinds of
optimizations (e.g., tail recursion).
In general, because Python's extremely
dynamic nature, it is impossible to do
the kind of compile-time optimization
known from functional languages like
Haskell or ML. And that's fine.

我从中抽出两件事:

  • 语言的创建者并不真正认为Python是一种功能性语言。因此,可以看到"功能型"功能,但您不太可能看到任何功能明确的功能。
  • Python的动态特性抑制了您在其他函数语言中看到的一些优化。当然,lisp和python一样动态(如果不是更动态的话),所以这只是部分解释。

  • 该方案没有代数数据类型或模式匹配,但它肯定是一种功能性语言。从函数式编程的角度来看,python令人讨厌的地方:

  • 残废的羔羊。因为lambda只能包含一个表达式,并且不能在表达式上下文中轻松地执行所有操作,这意味着可以定义"即时"的函数是有限的。

  • 如果是陈述,而不是表达。这意味着,除了其他事情之外,你不能有一个lambda,其中包含一个if。(这是用python 2.5中的三元语言修复的,但看起来很难看。)

  • guido威胁每隔一段时间就会删除映射、过滤和减少一次

  • 另一方面,python有词汇闭包、lambda和列表理解(不管guido是否承认,这实际上是一个"功能性"概念)。我在python中做了很多"功能风格"的编程,但我几乎不认为这是理想的。


    我从来不会称Python为"功能性的",但是每当我用Python编程时,代码总是几乎完全是功能性的。

    诚然,这主要是由于对列表的理解非常好。所以我不一定建议将python作为一种函数式编程语言,但我建议为任何使用python的人使用函数式编程。


    让我用一段代码演示一下"函数式"python问题的答案。

    Python:

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

    Haskell:

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

    这里的主要区别在于haskell的标准库在功能编程方面具有有用的功能:在这种情况下,iterateconcat(!!)


    对于这个问题(和答案)来说,真正重要的一点是:什么是函数式编程,它最重要的特性是什么?我将尝试给出我的观点:

    函数式编程很像在白板上写数学。当你写方程式的时候在白板上,您不会考虑执行命令。没有突变。你不会后天再来看,当你重新计算的时候,你会得到不同的结果(或者,如果你喝了一些新鲜的咖啡,你可能会)。基本上,板上有什么,你开始写的时候答案已经在那里了一切都结束了,你只是还没有意识到它是什么。

    函数式编程就是这样的,你不改变事情,你只是评估方程式(在本例中称为"程序")并找出答案。程序仍然存在,未修改。数据也是如此。

    我将以下列为函数式编程最重要的特性:a)参考透明度-如果您在其他时间评估同一声明和place,但使用相同的变量值,它的含义仍然相同。b)没有副作用-无论你盯着白板看多长时间,另一个方程式那个家伙正在看另一个白板,不会意外改变的。c)函数也是值。可以传递并应用于其他变量。d)函数组合,可以做h=g·f,从而定义一个新的函数h(..),即相当于调用g(f(..)。

    此列表按我的优先顺序排列,因此引用透明性是最重要的,之后没有副作用。

    现在,如果您通过python检查语言和库的支持情况,保证,这些方面-那么你就可以很好地回答你自己的问题了。


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

    它有一些额外的特性,所以对某些人来说还不够纯粹。

    它还缺少一些特性,因此对于某些人来说还不够完整。

    缺少的特性相对容易编写。在python的fp上查看类似的文章。


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


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

    不管怎样,事实证明,map( foo() , x ) * map( foo(), y )map( foo(), x * y )是一样的。后一种情况实际上比前一种情况更快,因为前者执行两个副本,后者执行一个副本。

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