跳转到内容

函数式编程基础

来自维基教科书,开放的书籍,开放的世界

PAPER 2 - ⇑ 函数式编程基础 ⇑

什么是函数式编程 函数式编程基础 →


函数式编程是一种 声明式 编程范式,其中程序被编写为数学函数,其执行顺序并非完全由程序员定义。这些数学函数会生成一致的输出,这些输出完全依赖于输入。函数可以由其他函数构建,也可以递归地调用自身。函数式编程在几个方面不同于 命令式编程范式

函数的输出取决于输入,而不是程序的不断变化的状态,函数式编程是无状态的。例如,下面的 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 的值

函数式编程,fudgeNumbers
只返回值,它不会更改
其作用域之外的任何内容

函数式编程还避免使用在运行时发生变化的变量,数据结构被认为是 不可变的

Python 示例 Haskell 示例
a = 2
b = 5
c = a + b
a = 6
a = 2
b = 5
c = a + b
不是函数式编程,因为它
在运行时更改 a 的值

函数式编程,变量只声明一次

函数式编程范式 - 计算是对避免副作用和在运行时更改变量的数学函数的求值


函数式编程范式的优势包括

  • 支持将计算问题分解和抽象成函数,这些函数由其他函数组成,而其他函数又由其他函数组成,等等。
  • 更易于阅读和理解代码。
  • 更易于调试代码,因为每个函数都可以单独测试,并且不依赖于机器的状态。
  • 适合于运行并行和并发程序执行,允许函数式程序在多处理器系统上运行。

Lisp 是最早的函数式编程语言之一,诞生于 1958 年。Lisp 的几种方言仍在普遍使用,包括 Common LispScheme。其他函数式编程语言包括 ErlangHaskell。虽然命令式编程语言比纯函数式语言更常用,但可以使用许多现代语言进行函数式编程。其他支持函数式编程的语言包括 PythonC#F#JavaVisual Basic .NETJavaScript

Scheme 代码示例
 (defun factorial (n)
   (if (= n 0) 1
       (* n (factorial (- n 1)))))

首次使用 Haskell

[编辑 | 编辑源代码]

本章中的大多数代码示例将使用 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
练习:函数式编程基础

什么是函数式编程语言?

答案

函数式编程语言是一种代码没有副作用、程序执行是无状态的,并且函数的输出仅取决于输入的语言。

描述使用函数式编程语言的两个好处

答案

  • 更易于调试
  • 更易于阅读和理解
  • 可以在并行系统上运行


解释为什么这不能被认为是函数式编程的示例?

...
def multiply (a):
   return a * b
...

答案

我们不知道 b 在运行时的值,因此 multiply 函数会根据计算机的状态输出不同的值。


华夏公益教科书