C++角度的go函数式编程|青训营笔记

53 阅读2分钟

这是我参与[第五届青训营]的第十一天。

函数式编程(functional programming)是一种编程设计模范(paradigm)。主要思想见于lisp和ml家族的编程语言。函数式编程易于平行处理。大数据框架Hadoop和Spark的思想,也基于函数式编程。

函数式编程的基本前提是函数为一级对象,即认为函数也是值,可以作为参数也可以作为返回值。

package main
import (
    "fmt"
)
func main() {
    f := func() {
        fmt.Println("Hellow World")
    }
    
    f()
}

在上面的例子中,定义了一个函数对象f,并调用它。

高阶函数

也可以将函数对象作为另一个函数的参数,这种函数成为高阶函数(higher-order function)。

package main 
import ( 
    "fmt" 
) 
func apply(arr []float64, callback func(float64) float64) []float64 { 
    out := make([]float64, len(arr)) 
    for i, e := range arr { 
        out[i] = callback(e) 
    } 
    return out 
} 
func main() { 
    arr := []float64{1, 2, 3, 4, 5} 
    // Square 
    sqr := apply(arr, func(n float64) float64 { 
        return n * n 
    }) 
    fmt.Println(sqr) 
    // Cubic 
    cub := apply(arr, func(n float64) float64 { 
        return n * n * n 
    }) 
    fmt.Println(cub) 
    // Inverse 
    inv := apply(arr, func(n float64) float64 { 
        return 1.0 / n 
    }) 
    fmt.Println(inv) 
}

在上例中,对同一个函数apply传入不同的函数,得到了不同的结果。

闭包

函数对象除了作为参数,也可以做为回传值。

package main

import (
    "log"
)

func run() func() int {
    n := -1
    
    return func() int {
        n += 1
        return n
    }
}

func main() {
    f := num()
    if !(f() == 0) {
        log.Fatal("Wrong number")
    }
    
    if !(f() == 1) {
        log.Fatal("Wrong number")
    }
    
    if !(f() == 2) {
        log.Fatal("Wrong number")
    }
}

在上例中,每次调用函数f,得到的数值会递增1,这种带有状态的函数,称为闭包(closure)

严格计算 和 惰性计算

主流的编程语言大多都是严格计算。 以下的go惰性计算是错误的:

package main

import (
     "fmt"
)

func main() {
    fmt.Println(len([]int{1, 2, 3 / 0, 4}))
}

这里一提,Haskell语言的上述表示是正确的,因为Haskell语言是惰性计算的特性。

main = print len

list = [1, 2, 3/0, 4]
len = length list

递归

递归不是函数式程序设计专有的特性,然而,函数式编程语言中支持尾部调用优化(tail-call optimization),使得递归和控制结构达到相近的速度,在go中没有实现这样的特性。