Please enable Javascript to view the contents

什么是函数式编程

 ·  ☕ 3 分钟

1. 什么是编程范式

编程范式是一类典型的编程规范。一方面提供了工程师对实体的建模方法,将物理世界与代码关联起来;另一方面也提供了工程师对代码程序的理解思路。

编程范式与编程语言属于多对多的关系。一种编程语言中,可能包含多种编程范式,例如,C++ 包含面向过程、面向对象等。一个编程范式,也有可能被多种编程语言实现,例如,JavaScript、Scale、Python 等都支持函数式编程。

2. 几种常见的编程范式

  • 命令式

一句一句告诉计算机怎么处理。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package main

import "fmt"

func main() {
	var a int = 1

LOOP:
	if a < 10 {
		a++
		goto LOOP
	}
	fmt.Printf("a = %d\n", a)
}
  • 声明式

仅告诉计算机想要什么,常见的 DSL 语言都是声明式的,例如 SQL、HTML 等。

1
SELECT * FROM Sites WHERE domain='www.chenshaowen.com'
  • 结构化

拆分模块,借助循环等增加控制逻辑。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
package main

import "fmt"

func main() {
	var a int = 1
	for a < 10{
		a ++
	}
	fmt.Printf("a = %d\n", a)
}
  • 面向过程

基于结构化,强调函数调用。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
package main

import "fmt"

func loop(a int) int{
	for a < 10 {
		a ++
	}
	return a
}

func main() {
	var a = loop(1)
	fmt.Printf("a = %d\n", a)
}
  • 面向对象

用类抽象实体,用对象表达实体。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
#!/usr/bin/python3

class Parent:
    def myMethod(self):
        print('调用父类方法')


class Child(Parent):
    def myMethod(self):
        print('调用子类方法')


c = Child()          # 子类实例
c.myMethod()         # 子类调用重写方法
  • 面向切片

将与模块无关的事情,放到外部完成,常见的实践方式是装饰器、中间件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
def mydeco(func):
    print('do some things')

    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper


@mydeco
def hello():
    print('hello')


if __name__ == "__main__":
    hello()
  • 面向接口

规定一组必须实现的方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

type Duck interface{
	ToDuck()
}

type Dock1 struct{
}

func (d Dock1) ToDuck(){
	fmt.Println("ga...")
}

func main(){
	var d Duck
	d = new(Dock1)
	d.ToDuck()
}
  • 函数式编程

用无状态的函数组合来描述程序逻辑。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
package main

import "fmt"

func add(a, b int) int {
	return a + b
}

func multi(a, b int) int {
	return a * b
}

func myCal(a, b func(int, int) int, c, d int) int {
	return b(a(c, d), a(c, -d))
}

func main() {
	var result = myCal(add, multi, 5, 1)
	fmt.Println(result)
}

3. 为什么选择函数式编程

  • 简化项目状态管理

管理复杂度是软件工程面临的挑战之一。对于工程师来说,管理程序运行的状态是编程的难点。函数式编程,强调的是无状态,除了 IO 处理,不需要维护程序本身的状态。

  • 更接近人类语言

函数式编程通常会借助声明式范式,以更接近人类语言的描述,告诉计算机做什么。而不是让人去模仿计算机的思考方式,一条指令一条指令地告诉计算机怎么做。

  • 更适合并发场景

由于函数式编程不维护状态,不存在锁的问题,并发问题可以在编译器、解释器层面解决,大大降低了编写高并发程序的难度。

  • 喜新厌旧,风格轮换

轮子总在被重新发明,很多思想在计算机发展的早期就已经出现,但不一定总有机会走到普罗大众面前。函数式编程、通信顺序进程等都是如此,包括云计算,风格总在轮换,具有一定的周期性。

4. 函数式编程的关键字

  • 纯函数

输出仅取决于输入。

  • 引用透明

函数可以被计算结果替代,而不影响调用它的程序。

  • 无副作用

不依赖外部状态。

  • 惰性求值

需要时才进行求值。

  • lambda

匿名函数,没有名字的函数。

  • 柯里化

将多参数函数改造为返回单参数、并能继续接收剩余参数的函数过程。

  • 高阶函数

接受函数作为参数或者返回函数的函数。


微信公众号
作者
微信公众号