對於一個數學專業畢業的學生,函數式編程自然的吸引力了我,從哥德爾的不完備定理,到邱奇的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是一門支持多編程範式的語言,在合適的地方使用合適的方法纔是咱們須要去作的。
本文版權屬於再惠研發團隊,歡迎轉載,轉載請保留出處。@白爾摩斯