对于一个数学专业毕业的学生,函数式编程自然的吸引力了我,从哥德尔的不完备定理,到邱奇的lambda演算,到柯里的组合子逻辑,无不吸引着我。 而swift做为一门多编程范式的语言,一样支持函数式编程。 不过函数式编程比较复杂,我也只是管中窥豹,谈谈本身在swift中的认识。node
函数式编程和命令式编程不同,进行纯函数式编程,因为没法进行赋值操做(不可变的数据结构),而在C或者是C++这样的语言中数据结构每每都是可变的,因此之前所学的数据结构和算法都没有什么用。 因为数据结构的不一样,禁止赋值,有额外的开销,算法也不同。算法
常见的数据结构编程
public class TreeNode { public var val: Int public var left: TreeNode? public var right: TreeNode? public init(_ val: Int) { self.val = val self.left = nil self.right = nil } } 复制代码
和它的插入算法swift
func insertIntoBST(_ root: TreeNode?, _ val: Int) -> TreeNode? { guard let rootNode = root else { return TreeNode(val) } if val < rootNode.val { rootNode.left = insertIntoBST(rootNode.left, val) } else { rootNode.right = insertIntoBST(rootNode.right, val) } return root } 复制代码
用函数式的数据结构表示api
indirect enum BST { case leaf case node(BST,Int,BST) init() { self = .leaf } init(_ value: Int) { self = .node(.leaf,value,.leaf) } } 复制代码
一样的,函数式的插入算法markdown
func insertIntoBST(_ root:BST, _ val:Int) -> BST { switch root { case .leaf: return BST(val) case let .node(left, value, right): if val < value { return BST.node(insertIntoBST(left, val), value, right) } else { return BST.node(left, value, insertIntoBST(right, val)) } } } 复制代码
能够看到因为不可变的数据结构,不能对树作修改,要实现插入算法,必须每次都建立新的树。数据结构
第一次接触swift最大的印象就是函数是一等公民,能够做为参数传递。app
好比下面这个fibF
数据结构和算法
func fib(_ n:Int) -> Int { if n < 2 { return n } else { return fib(n-1) + fib(n-2) } } let fibF = fib fibF(11) 复制代码
或者咱们不想显式的定义fib
这个函数,使用Z组合子函数式编程
func Z<T,U>(f:@escaping ((T) -> U, T) -> U) -> (T) -> U { return {(x:T) -> U in f(Z(f: f),x)} } let fibZ = Z(f: {$1 < 2 ? $1 : $0($1-1) + $0($1-2)}) fibZ(11) 复制代码
在系统提供的方法中也很常见,好比Array的sorted
方法就能够传一个函数
[1,2,3,4,5].sorted(by: >) 复制代码
一等函数的概念源自邱奇的lambda演算。 现代计算机采用的是冯诺伊曼结构,而冯诺依曼结构是图灵机的一个实现。然而在图灵为了解决断定性问题引入图灵机,和他同时代的天才,邱奇,在几个月前用lambda演算和递归函数,证实了相似的论题。这三个模型(图灵机,lambda演算和递归函数)计算能力等价(邱奇-图灵猜测)。
什么函数式编程呢,可能不少人最大的印象就是使用map和flatMap这样的高阶函数,固然这只是一部分
在swift中Optionals
和Collection
有map和flatMap函数 map函数
(1...10).map({"\($0)"}) 复制代码
flatMap函数
["Hi","Swift"].flatMap({$0}) 复制代码
为何Optionals
和Array
会有一样的名称的方法? 这些map和flatMap方法是否遵照相同的逻辑?
咱们能够看下swift中对Optionals
的map函数的定义
@inlinable public func map<U>(_ transform: (Wrapped) throws -> U) rethrows -> U? 复制代码
对Array
的map函数定义
@inlinable public func map<T>(_ transform: (Bound) throws -> T) rethrows -> [T] 复制代码
Haskell中Functor
有个函数fmap
(swift中的map)
fmap :: (a -> b) -> [a] -> [b] 复制代码
因此它们被称为Functor(函子)
相应的查看一下swift中对flatMap的定义
//Optionals @inlinable public func flatMap<U>(_ transform: (Wrapped) throws -> U?) rethrows -> U? //Array @inlinable public func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence 复制代码
Haskell中Monad
对函数>>=
的定义(swift中的flatMap)
(>>=) :: m a -> (a -> m b) -> m b
复制代码
翻译成swift就是(伪代码)
func flatMap<A,B>(x:F<A>)(_ transform: (A) -> F<B>) -> F<B> 复制代码
可见Optionals
和Array
都是Monad
swift虽然支持函数式编程,然而在实际开发的时候,纯函数编程并不是好的选择,由于传统的算法和数据结构都是以图灵机和过程式语言为基础,并且因为数据的不可变性放弃了执行机能够反复擦写内存属性,因此并不能作到高效的算法,不能保证性能,可是好在swift是一门支持多编程范式的语言,在合适的地方使用合适的方法才是咱们须要去作的。
本文版权属于再惠研发团队,欢迎转载,转载请保留出处。@白尔摩斯