目录

    1. 什么是编程范式

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

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

    2. 几种常见的编程范式

    • 命令式

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

    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 等。

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

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

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

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

    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)
    }
    
    • 面向对象

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

    #!/usr/bin/python3
    
    class Parent:
        def myMethod(self):
            print('调用父类方法')
    
    
    class Child(Parent):
        def myMethod(self):
            print('调用子类方法')
    
    
    c = Child()          # 子类实例
    c.myMethod()         # 子类调用重写方法
    
    • 面向切片

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

    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()
    
    • 面向接口

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

    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()
    }
    
    • 函数式编程

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

    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

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

    • 柯里化

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

    • 高阶函数

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