# Swift 函数式编程 ## 定义 函数式编程(Funtional Programming,简称 FP)是一种编程范式,也就是如何编写程序的方法论 - 主要思想:把计算过程尽量分解成一系列可复用函数的调用 - 主要特征:函数是“第一等公民”。函数与其他数据类型一样的地位,可以赋值给其他变量,也可以作为函数参数、函数返回值 函数式编程最早出现在 LISP 语言,绝大部分的现代编程语言也对函数式编程做了不同程度的支持,比如:Haskell、JavaScript、Python、Swift、Kotlin、Scala 等 函数式编程中几个常用的概念: - Higher-Order Function、Function Currying - Functor、Applicative Functor、Monad ## 高阶函数 高阶函数是至少满足下列一个条件的函数: - 接受一个或多个函数作为输入(map、filter、reduce等) - 返回一个函数 FP中到处都是高阶函数 ## 柯里化(Currying) 将一个接受多个参数的函数变换成为一系列只接受单个参数的函数 Demo: ```swift // 函数式编程,为了过程的复用 let num = 10 func add(_ v: Int) -> (Int) -> Int {{ $0 + v }} func sub(_ v: Int) -> (Int) -> Int { { $0 - v } } func multiple( _ v: Int) -> (Int) -> Int { { $0 * v }} func divide(_ v: Int) -> (Int) -> Int { { $0 / v } } func mod(_ v: Int) -> (Int) -> Int { { $0 % v }} // 函数合成,范型 infix operator >>> : AdditionPrecedence func >>>(_ f1: @escaping (A) -> B, _ f2: @escaping (B) -> C) -> (A) -> C { { f2(f1($0)) } } // result = ((((x + 3)*5) - 1 )%10)/2 let fn = add(3) >>> multiple(5) >>> sub(1) >>> mod(10) >>> divide(2) print(fn(num)) func multipleAdd(_ v1: Int) -> ((Int) -> ((Int) -> Int)) { return { v2 in return { v3 in return v1 + v2 + v3 } } } /* - multipleAdd(1),调用函数,传递1给参数V3,此时继续返回一个函数。 - multipleAdd(1)(2) 拿着上一步返回的函数,再去调用,传入的2给参数V2.此时继续返回一个函数 - multipleAdd(1)(2)(3) 拿着上一步返回的函数,再去调用,此时传入的3给参数V1,此时则执行相加操作。V1 + V2 + V3 */ let rs = multipleAdd(1)(2)(3) print(rs) ``` 参数对应如下图圈选部分 Demo2:将一个三个参数的函数变成柯里化 ```swift func add(_ v1: Int, _ v2: Int) -> Int { v1 + v2 } func multipleAdd(_ v1: Int, _ v2: Int, _ v3: Int) -> Int { v1 + v2 + v3 } func currying(_ fn: @escaping (A, B) -> C) -> ((A) -> ((B) -> C)) { return { a in return { b in return fn(a, b) } } } func currying(_ fn: @escaping (A, B, C) -> D) -> ((A) -> ((B) -> ((C) -> D ))) { return { a in return { b in return { c in return fn(a, b, c) } } } } let rs1 = currying(add)(10)(20) let rs2 = currying(multipleAdd)(10)(20)(30) print(rs1, rs2) // 30 60 ``` ## 函子 像 Array、Optional 这样支持 map 运算的类型,称为函子(Functor) ```swift // Array public func map(_ transform: (Element) -> T) -> Array // Optional public func map(_ transform: (Wrapped) -> U) -> Optional ``` ## 适用函子(Applicative Functor) 对任意一个函子 F,如果能支持以下运算,该函子就是一个适用函子 ```swift func pure(_ value: A) -> F func <*>(fn: F<(A) -> B>, value: F) -> F ``` Array 可以成为适用函子 ```swift func pure(_ value: A) -> [A] { [value] } infix operator <*> : AdditionPrecedence func <*>(fn:[(A) -> B], value: [A]) -> [B] { var resultArray: [B] = [] if fn.count == value.count { for i in fn.startIndex.. [1, 2, 3] print(array) // console [10] [2, 12, -2] ``` ## 单子 对任意一个类型 F,如果能支持以下运算,那么就可以称为是一个单子(Monad) ```swift func pure(_ value: A) -> F func flatMap(_ value: F, _ fn: (A) -> F) -> F ``` 很显然,Array、Optional 都是单子 “单子”(Monad)是一个抽象概念,它代表了一种设计模式,用于组合计算并管理可能包含副作用的值。单子是一种在函数式编程中用于封装和组合计算的通用结构,它允许程序员以一致的方式处理各种复杂的计算情况,包括错误处理、异步操作、状态管理等。 单子通常定义了几个操作,这些操作允许你以统一的方式对封装在单子中的值进行操作。这些操作包括: - `return` 或 `pure`:将一个值“提升”到单子中。 - `bind` 或 `flatMap`:用于组合单子中的计算,允许你将一个单子的输出作为另一个单子的输入。 在 Swift 中,单子并没有像在其他一些语言(如 Haskell 或 Scala)中那样作为语言内建的概念,但你可以通过定义自己的类型和方法来实现单子模式。例如,Swift 中的 `Optional` 类型可以看作是一个简单的单子,它表示一个值可能存在或不存在。`Optional` 提供了 `map` 和 `flatMap` 方法,允许你对封装的值进行链式操作。 其他常见的单子实现包括处理异步操作的单子(如 Promise 或 Future),处理错误和异常的单子,以及管理状态的单子(如 State Monad)。 单子提供了一种强大的方式来管理复杂性和副作用,使代码更易于理解和测试。然而,它们也增加了抽象层次,可能需要一些时间来适应和理解。在 Swift 中,你可以根据自己的需要选择是否使用单子,以及使用哪种类型的单子。