函数式编程基础
有关 A 级(及更高)函数式编程的更深入概述,请查看 Richard Pawson 的 计算机科学从金属向上 |
此页面上的资料最初是为 isaac 计算机科学 编写的 |
函数式编程是一种 声明式 编程范式,其中程序被编写为数学函数,其执行顺序并非完全由程序员定义。这些数学函数会生成一致的输出,这些输出完全依赖于输入。函数可以由其他函数构建,也可以递归地调用自身。函数式编程在几个方面不同于 命令式编程范式
函数的输出仅取决于输入,而不是程序的不断变化的状态,函数式编程是无状态的。例如,下面的 Python 程序两次调用相同的函数 addNumbers
,参数相同 2,2
,但返回了不同的值,因为程序的状态(此处通过变量 c
模拟)发生了变化。在函数式编程语言中不会发生这种情况,因为无论何时使用相同的参数调用函数,都会生成相同的输出。
Python 示例 | Haskell 示例 |
---|---|
def addNumbers (a, b):
return a + b + c
...
print(addNumbers(2,2)) # prints 8
...
print(addNumbers(2,2)) # prints 6
|
addNumbers a b c = a + b + c
...
addNumbers 2 2 2 --returns 6
...
addNumbers 2 2 2 --returns 6
|
不是函数式编程,因为 addNumbers 使用全局变量 c |
函数式编程,addNumbers 返回的值仅取决于输入 |
函数式编程语言避免副作用。副作用是指函数修改其局部环境之外的内容。在下面的示例中,函数 fudgeNumbers
在运行时会更改全局变量 g
。
Python 示例 | Haskell 示例 |
---|---|
g = 0
def fudgeNumbers (a, b):
global g
g = a + (2 * b)
return a * b
print(g) # prints 0
print(fudgeNumbers(2,2)) # prints 4
print(g) # prints 6
|
g = 0
fudgeNumbers a b = a + b
g --returns 0
fudgeNumbers 2 2 --returns 4
g --returns 0
|
不是函数式编程,因为 fudgeNumbers 会更改运行时全局变量 g 的值 |
函数式编程, |
函数式编程还避免使用在运行时发生变化的变量,数据结构被认为是 不可变的。
Python 示例 | Haskell 示例 |
---|---|
a = 2
b = 5
c = a + b
a = 6
|
a = 2
b = 5
c = a + b
|
不是函数式编程,因为它 在运行时更改 a 的值 |
函数式编程,变量只声明一次 |
函数式编程范式的优势包括
- 支持将计算问题分解和抽象成函数,这些函数由其他函数组成,而其他函数又由其他函数组成,等等。
- 更易于阅读和理解代码。
- 更易于调试代码,因为每个函数都可以单独测试,并且不依赖于机器的状态。
- 适合于运行并行和并发程序执行,允许函数式程序在多处理器系统上运行。
Lisp 是最早的函数式编程语言之一,诞生于 1958 年。Lisp 的几种方言仍在普遍使用,包括 Common Lisp 和 Scheme。其他函数式编程语言包括 Erlang 和 Haskell。虽然命令式编程语言比纯函数式语言更常用,但可以使用许多现代语言进行函数式编程。其他支持函数式编程的语言包括 Python、C#、F#、Java、Visual Basic .NET 和 JavaScript。
Scheme 代码示例 |
---|
(defun factorial (n)
(if (= n 0) 1
(* n (factorial (- n 1)))))
|
本章中的大多数代码示例将使用 Haskell。您可以在 Learn You a Haskell for Great Good! 上了解有关 Haskell 的更多信息。要执行本章中显示的示例,您可以下载开源的 Glasgow Haskell Compiler 或 GHC。大多数示例可以直接写入 GHC 提供给您的命令行界面,如下所示,带有 .>
符号。例如
.> putStrLn "Hello World!"
Hello World!
.> 4 ^ 7
16328
.> [1..8]
[1,2,3,4,5,6,7,8]
.> round 7.8
8
后面的示例可能需要您编写多行程序,尤其是在您需要声明自己的函数时,为此,您需要打开文本编辑器并将您的 Haskell 文件保存为 .hs
扩展名。例如
myFirstHaskell.hs |
---|
myFactorial :: (Integral a) => a -> a
myFactorial 0 = 1
myFactorial n = n * factorial (n - 1)
|
然后,我们可以使用 :l
(加载)命令将此加载到 GHC 中,后跟文件位置和名称。
.> :l myFirstHaskell.hs
[1 of 1] Compiling Main ( myFirstHaskell.hs, interpreted )
Ok, modules loaded: Main.
现在,我们可以从命令行使用已加载的函数 myFactorial
.> myFactorial 4
24
还有其他 Haskell 开发环境可用,包括 repl.it |
练习:函数式编程基础 什么是函数式编程语言? 答案 函数式编程语言是一种代码没有副作用、程序执行是无状态的,并且函数的输出仅取决于输入的语言。 描述使用函数式编程语言的两个好处 答案
解释为什么这不能被认为是函数式编程的示例? ...
def multiply (a):
return a * b
...
答案 我们不知道
|