函数式编程
函数式编程
(Funtional Programming, 简称FP)是一种编程范式,主要思想就是把计算过程尽量分解成一系列可复用函数的调用。
函数式编程传统写法
假设要实现以下功能:[(num + 3) * 5 - 1] % 10 / 2
// 自定义实现函数方法
// 加法
func add(_ v1: Int, _ v2: Int) -> Int { v1 + v2 }
// 减法
func sub(_ v1: Int, _ v2: Int) -> Int { v1 - v2 }
// 乘法
func multiple(_ v1: Int, _ v2: Int) -> Int { v1 * v2 }
// 除法
func devide(_ v1: Int, _ v2: Int) -> Int { v1 / v2 }
// 求余
func mob(_ v1: Int, _ v2: Int) -> Int { v1 % v2 }
那么传统的调用方式就是如下:
devide(mod(sub(multiple(add(num, 3), 5), 1), 10), 2)
这样也能满足需求,但这种调用方式可读性非常差, 我们来实现一个简单的add
函数式编程:
class FunctionTest {
// 接收一个参数,返回一个函数(返回的函数也接收一个参数)
func add(_ v: Int) -> (Int) -> Int {
// 返回闭包表达式
return {
// $0 代表返回出去的函数被调用的参数
$0 + v
}
}
func test() {
let num = 3;
// fn是一个函数, 参数3是传给了add方法的v,
let fn = self.add(3);
// 调用返回的函数, 也可以合并成一句self.add(3)(num)
// 参数num是传给了闭包表达式的$0
fn(num)
}
}
这样就实现了函数式调用
(把计算过程尽量分解成一系列可复用函数的调用)
因为fn接收了一个参数,返回了一个函数,假设我们要实现 100 + 3,就可以这样:
fn(100)
同理,我们实现以下其他几个方法的函数式写法:
// 减
func sub(_ v: Int) -> (Int) -> Int {
return {
$0 - v
}
}
// 乘
func multiple(_ v: Int) -> (Int) -> Int {
return {
$0 * v
}
}
// 除
func devide(_ v: Int) -> (Int) -> Int {
return {
$0 / v
}
}
// 求余
func mod(_ v: Int) -> (Int) -> Int {
return {
$0 % v
}
}
如上,我们已经实现了函数式的写法,但实际上在调用时,还是需要这样写:
let num = 1;
let fn1 = add(3)
let fn2 = multiple(5)
let fn3 = sub(1)
let fn4 = mod(10)
let fn5 = devide(2)
print(fn5(fn4(fn3(fn2(fn1(num))))))
相比于之前的写法,好了那么一点点,但还是不够简洁。此时我们需要进行函数合成
函数合成
函数合成
是将一个函数的结果作为另一个函数的参数传入,最终返回出一个函数, 比如:
// @escaping:逃逸闭包
// 接收两个函数, 将f1的结果作为f2的参数传入,
// 执行完在返回出去(返回一个函数接收一个Int参数,返回值Int)
func composite(_ f1: @escaping (Int) -> Int,
_ f2: @escaping (Int) -> Int)
-> (Int)-> Int {
return {
f2(f1($0))
}
}
使用函数合成
后大大的简洁了方法的调用链, 就可以这样调用了:
let num = 1
// add(3)的结果作为multiple(5)的参数传入
let fn = composite(add(3), multiple(5))
print(fn(num)) // 输出20
还有另外一种函数合成
的写法:
infix operator >>> : AdditionPrecedence
func >>>(_ f1: @escaping (Int) -> Int,
_ f2: @escaping (Int) -> Int)
-> (Int)-> Int {
return {
f2(f1($0))
}
}
用泛型约束一下类型就是:
infix operator >>> : AdditionPrecedence
func >>><A, B, C>(_ f1: @escaping (A) -> B,
_ f2: @escaping (B) -> C)
-> (A)-> C {
return {
f2(f1($0))
}
}
那么调用的时候就只需要这么写了:
let fn = add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> devide(2)
更加简洁了!
本文首次发布于 孙忠良 Blog, 作者 [@sunzhongliang] , 转载请保留原文链接.