我可以列举函数式编程的许多特性,但是当我的朋友问我你能为我定义函数式编程吗?我不能。
8 回答
我想说纯函数式编程的定义点是所有计算都在没有副作用的函数中完成。也就是说,函数接受输入和返回值,但不改变任何隐藏状态。在这个范式中,函数更接近地模拟它们的数学表亲。
当我开始使用 Erlang 时,我就确定了这一点,Erlang 是一种具有一次写入堆栈的语言。但是,应该澄清的是,编程范式和编程语言之间是有区别的。通常被称为函数式的语言提供了许多鼓励或强制执行函数式范式的特性(例如,Erlang 的一次写入堆栈、高阶函数、闭包等)。然而,函数式编程范式可以应用于许多语言(有不同程度的痛苦)。
到目前为止,许多定义都强调了纯度,但是有许多语言被认为是函数式的,它们根本不是纯粹的(例如,ML、Scheme)。我认为使语言“功能化”的关键属性是:
- 高阶函数。函数是一种内置数据类型,与整数和布尔值没有什么不同。匿名函数很容易创建和惯用(例如,lambdas)。
- 一切都是一种表达。在命令式语言中,语句(改变状态并影响控制流)和表达式(产生值)之间存在区别。在函数式语言(甚至是非纯函数式语言)中,表达式求值是执行的基本单元。
鉴于这两个属性,您自然会得到我们认为是函数的行为(例如,用折叠和映射表示计算)。消除可变状态是一种让事情变得更加实用的方法。
来自维基百科:
在计算机科学中,函数式编程是一种编程范式,它将计算视为对数学函数的评估,并避免了状态和可变数据。它强调函数的应用,与强调状态变化的命令式编程风格形成对比。
使用函数式方法具有以下好处:
- 在函数式语言中,并发编程要容易得多。
- FP 中的函数永远不会产生副作用——这使得单元测试更加容易。
- 生产环境中的热代码部署要容易得多。
- 函数式语言可以用数学方法进行推理。
- 惰性评估为性能优化提供了潜力。
- 更具表现力——闭包、模式匹配、高级类型系统等让程序员更容易“说出他们的意思”。
- 简洁——对于某些类的程序,功能解决方案要简洁得多。
有一篇很棒的文章,这里有更多详细信息。
能够列举特征比试图定义术语本身更有用,因为人们将在各种上下文中使用术语“函数式编程”,在一个连续统一体中具有多种含义,而各个特征具有单独更清晰的定义,得到更普遍的认同。
以下是想到的功能。大多数人使用术语“函数式编程”来指代这些功能的某些子集(最常见/最重要的是“纯度”和“高阶函数”)。
FP特点:
- 纯度(又名不变性,避免副作用,引用透明性)
- 高阶函数(例如,将函数作为参数传递,将其作为结果返回,将匿名函数动态定义为 lambda 表达式)
- 懒惰(又称非严格评估,与纯度相结合时最有用/可用)
- 代数数据类型和模式匹配
- 闭包
- 柯里化/部分应用
- 参数多态性(又名泛型)
- 递归(由于纯度而更加突出)
- 使用表达式而不是语句进行编程(再次,从纯粹性)
- ...
您使用的上述列表中的功能越多,就越有可能有人将您正在做的事情标记为“函数式编程”(前两个功能 - 纯度和高阶函数 - 可能值得获得最多的额外奖励积分你的“FP分数”)。
我必须补充一点,函数式编程也倾向于抽象程序和域的控制结构 - 例如,您不再对某些事物列表执行“for循环”,而是将其“映射”到某个函数以生成输出。
我认为函数式编程是一种心态以及上面给出的定义。
有两个独立的定义:
Chris Conway 给出了较旧的定义(一等函数)。
John Stauffer 给出了较新的定义(避免突变等副作用)。这通常被称为纯函数式编程。
这是很多混乱的根源......
这就像使用矢量而不是位图来绘制图片 - 告诉画家如何更改图片而不是每一步图片的样子。
它是函数的应用,而不是改变状态。
我认为 John Stauffer 主要有这个定义。我还要补充一点,您需要能够传递函数。本质上,您需要高阶函数,这意味着您可以轻松地传递函数(尽管传递块就足够了)。
例如,一个非常流行的函数调用是 map。基本上相当于
list is some list of items
OutList is some empty list
foreach item in list
OutList.append(function(item))
return OutList
因此代码表示为 map(function, list)。革命性的概念是功能就是功能。Javascript 是具有高阶函数的语言的一个很好的例子。基本上,函数可以被视为变量并传递给函数或从函数返回。C++ 和 C 具有可以类似使用的函数指针。.NET 委托也可以类似地使用。
然后你可以想到各种很酷的抽象......
你有 AddItemsInList、MultiplyItemsInList 等函数吗?
每个函数接受 (List) 并返回一个结果
您可以创建(注意,许多语言不允许您+
作为函数传递,但这似乎是表达概念的最清晰方式)......
AggregateItemsInList(List, combinefunction, StepFunction)
增量函数适用于索引......更好的是使用列表操作(如 next 和 for incTwo next 如果存在)使它们在列表上工作......
function incNormal(x) {
return x + 1
}
function incTwo(x) {
return x + 2
}
AggregateItemsInList(List, +, incNormal)
想要做其他所有项目吗?
AggegateItemsInList(List, +, incTwo)
想要倍增?
AggregateItemsInList(List, *, incNormal)
想要将考试成绩加在一起?
function AddScores (studenta, studentb) {
return studenta.score + studentb.score
}
AggregateItemsInList(ListOfStudents, AddScores, incOne)
高阶函数是一个非常强大的抽象。不必为数字、字符串、学生等编写自定义方法。您有一个聚合方法可以循环遍历任何内容的列表,您只需为每种数据类型创建加法操作。