函数式编程的核心概念是什么?
在面向对象编程中,我们可能会说核心概念是:
- 封装
- 遗产,
- 多态性
那么在函数式编程中呢?
关于函数式编程的基本概念没有社区共识。 在为什么函数式编程问题(PDF) ,约翰休斯认为,他们是高阶函数和懒惰的评价。 佩戴头发衬衫:对哈斯克尔的回顾 Simon Peyton Jones说真正的本质不是懒惰而是纯洁。 理查德·伯德会同意。 但是有大量的Scheme和ML程序员非常乐意编写带有副作用的程序。
作为已经实践和教授了二十年function编程的人,我可以给你一些被广泛认为是函数式编程核心的想法:
-
以适当的词汇范围为基础的嵌套,一stream的function是核心。 这意味着您可以在运行时创build一个匿名函数,其自由variables可以是封闭函数的参数或局部variables,并且您可以返回一个值,将其放入数据结构中,等等。 (这是高阶函数的最重要forms,但是一些高阶函数(如
qsort
!)可以用C语言编写,这不是一种函数式语言)。 -
用其他function组合function来解决问题的手段。 没有人比约翰·休斯做得更好。
-
许多function程序员认为纯粹(从影响的自由,包括突变,I / O和exception)是函数式编程的核心。 许多function程序员不。
-
多态性 ,无论是否由编译器强制执行,都是函数式程序员的核心价值。 令人困惑的是,C ++程序员把这个概念称为“generics编程”。 当多态性被编译器强制执行时,它通常是Hindley-Milner的变种,但更强大的System F也是函数式语言的强大基础。 使用Scheme,Erlang和Lua等语言,可以在没有静态types系统的情况下进行函数式编程。
-
最后,绝大多数function程序员都相信归纳定义的数据types的价值,有时称为“recursiontypes”。 在具有静态types系统的语言中,这些语言通常被称为“代数数据types”,但即使在为Scheme开发人员编写的材料中 ,也可以find归纳定义的数据types。 感应定义的types通常附带一种称为模式匹配的语言特征,它支持非常一般的案例分析。 通常编译器可以告诉你,如果你忘记了一个案件。 我不想没有这种语言function的程序(奢侈品一旦采样成为必需品)。
在计算机科学中,函数式编程是一种将计算看作是math函数的评估并避免状态和可变数据的编程范例。 它强调function的应用,与强调状态变化的命令式编程风格形成鲜明对比。 函数式编程的根源在于lambda演算,这是20世纪30年代为了研究函数定义,函数应用和recursion而开发的一个正式系统。 许多函数式编程语言可以被看作lambda微积分的修饰。 – 维基百科
简而言之,
- Lambda微积分
- 高阶函数
- 不变性
- 无副作用
不是直接回答你的问题,但我想指出,“面向对象”和函数式编程并不一定矛盾。 你引用的“核心概念”有更多的通用对应物,它们也适用于函数式编程。
封装,更一般地说,是模块化。 所有我知道的纯function语言都支持模块化编程 。 你可能会说这些语言比典型的“OO”更好地实现了封装,因为副作用破坏了封装, 纯function没有副作用 。
inheritance,更一般地说,是逻辑蕴涵 ,这是一个函数所代表的。 规范subclass -> superclass
关系是一种隐式函数。 在函数式语言中,这是用typestypes或蕴涵来expression的(我认为蕴含是这两者中更一般的)。
“OO”学校的多态性是通过分类(inheritance)来实现的。 有一种更为普遍的多态称为参数多态 (又名generics),你会发现纯函数式编程语言会支持这种多态 。 此外,有些支持“更高types”,或更高阶的generics(又名types构造多态 )。
我想说的是,你的“面向对象的核心概念”在任何方面都不是面向对象的。 举个例子,我认为实际上OO没有任何核心概念。
抽象,通过参数化expression式的某个部分来创build函数的过程。
应用程序,通过用特定值replace参数来评估函数的过程。
在某种程度上,这就是它的一切。
让我重复我在class加罗尔函数式编程小组讨论的答案:
function程序仅包含function。 函数计算来自其input的值。 我们可以将其与命令式编程进行对比,在程序执行时,可变位置的值会改变。 换句话说,在C或Java中,名为X的variables指的是其值发生变化的位置。 但在函数式编程中,X是一个值的名称(不是位置)。 在范围内的任何地方,它具有相同的值(即它是引用透明的)。 在FP中,函数也是值。 它们可以作为parameter passing给其他函数。 这被称为高阶函数式编程。 高阶函数让我们模拟出各种各样的模式。 比如,看看Lisp中的map函数。 它代表了程序员需要对列表中的每个元素做“某事”的模式。 这个“东西”被编码为一个函数,并作为一个parameter passing给地图。
正如我们所看到的,FP最显着的特点就是副作用的自由度。 如果一个函数不仅仅是从它的input中计算出一个值,而且还会导致一个副作用。 这种function在纯FP中是不允许的。 testing副作用自由function很容易。 运行testing前没有全局状态设置,运行testing后没有全局状态检查。 每个function都可以通过提供input和检查返回值来独立testing。 这使得编写自动化testing变得容易。 副作用自由度的另一个好处是它可以更好地控制并行性。
许多FP语言正确地处理recursion和迭代。 他们通过支持称为尾recursion的方法来实现这一点。 尾recursion是什么 – 如果一个函数调用它自己,并且它是最后一件事情,它会马上删除当前的栈帧。 换句话说,如果一个函数以尾recursion的方式调用1000次,它不会将堆栈增长1000倍。 这使得这些语言中不需要特殊的循环结构。
Lambda微积分是FP语言最简单的版本。 像Haskell这样的更高层次的FP语言被编译成Lambda微积分。 它只有三个语法结构,但它仍然足以expression任何抽象或algorithm。
我的看法是FP应该被看作是一个元范式。 我们可以使用Lambda微积分提供的简单函数抽象来编写任何风格的程序,包括OOP。
谢谢,维杰
原讨论链接: http : //groups.google.co.in/group/bangalore-fp/browse_thread/thread/4c2cfa7985d7eab3