swift 之函數式編程(一)

1. 什麼是函數式編程?python

函數式編程是阿隆佐思想的在現實世界中的實現, 它將電腦運算視爲數學上的函數計算,而且避免使用程序狀態以及異變物件。 函數式編程的最重要基礎是λ演算。並且λ演算的函數能夠接受函數當做輸入(引數)和輸出(傳出值),函數式編程更加強調程序執行的結果而非執行的過程,倡導利用若干簡單的執行單元讓計算結果不斷漸進,逐層推導複雜的運算,而不是設計一個複雜的執行過程。函數式編程的殺手鐗正是當今世界上日益增加的並行性編程和元數據編程趨勢。其主要思想就是把運算過程儘可能寫成一系列嵌套的函數調用git

2. 函數式編程的特色:程序員

  • 函數是「第一等公民」:函數與其餘數據類型同樣,處於平等地位,能夠賦值給其餘變量,也能夠做爲參數,傳入另外一個函數,或者做爲別的函數的返回值
  • 只用「表達式」,不用語句:「表達式」--是一個單純的運算過程,老是有返回值; ‘語句’--執行某種操做,沒有返回值。函數式編程要求,只用表達式,不使用語句,也就是說,每一步都是單純的運算,並且沒有返回值。但在實際的I/O是不可能的,所以,編程過程當中,函數式編程只要求把I/O限制到最小,不要有沒必要要的讀寫行爲,保持計算過程的單純性。
  • 沒有反作用:函數要保持獨立,全部的功能就是返回一個新的值,沒有其餘行爲,尤爲是不得修改外部變量的值
  • 不修改狀態: 函數式編程只是返回新的值,不修改系統變量。
  • 引用透明: 函數的運行不依賴於外部變量或"狀態",只依賴於輸入的參數,任什麼時候候只要參數相同,引用函數所獲得的返回值老是相同的

3.入手一門新的語言的 時候,通常關注的內容有:
1.原生的數據結構
2.運算符
3.分支控制
4.若是是面向對象的編程語言,其面向對象的實現是怎樣的
5.若是是函數式編程語言,其面向函數式編程的實現是怎麼樣的
6.若是是面向接口的編程語言,器面向接口是如何實現的
7.若是是支持泛型編程,那麼又是如何實現的
 
 
4.對於支持函數式編程的語言,其通常的特色可能包含如下幾種:
1. 支持遞歸
2. 函數自己是語言First Class 的組成要素,且支持高階函數和閉包
3. 函數調用盡量沒有反作用(Side Effect)的條件 
    前面的一、2 swift是毋庸置疑的。對於條件3:
    爲了減小函數的反作用,不少函數式編程語言都力求達到所謂的「純函數」。純函數是指函數與外界交換數據的惟一渠道是 參數和返回值,而不會受到外部變         量的干擾。這彷佛是跟閉包的概念相抵觸。由於閉包自己的一個重要的特色就是能夠訪問到函數定義時的上下文環境。由於閉包自己的一個重要的特色就是能夠       訪問到函數定義時的上下文環境。
           事實上,爲了支持這種狀況下的純函數,一些編程語言提供的數據結構式不可變的(Persist)。好比說,在 Python 中,字符串 str就是一類不可變的數據       結構。 你不能在原來的字符串上進行修改,每次想要進行相似的操做,其實都是生成了一個新的 str對象。 然而 Python 中的鏈表結構則是可變的。
a = "hello ,"
b = a 
a += 'world'
print a   # hello ,world
print b   # hello ,

    swift中更多的是值類型,而不是引用類型,你會發現Int,Float,String,Array,Dictionary等都是Struct類型,而Struct都是值類型【暗示告終構體應該主要         用於封裝數據】,固然Enum也是值類型github

     在swift中區分值類型和引用類型是爲了將可變和不可不區分開來。值類型的數據傳遞給函數,函數內部能夠自由拷貝,改變值,而不用擔憂產生反作用。在多線      程環境下,多個線程同時運行,可能會意外錯誤地修改數據,這經常會是一種難以調試的bug。而使用值類型,你能夠安全地在線程間傳遞數據,由於值類型傳遞      是拷貝,因此無需在線程間同步數據變化。這就能夠保證代碼線程環境下的安全性。編程

     swift中的參數定義中加入inout,這樣的話就能夠經過參數來修改變量。這個特性頗有C的風格。swift

     使用swift自帶的數據結構並不能很好的的實現「無反作用」的「純函數式」編程。幸虧做爲一種關注度很高的語言, 已經有開發者爲其實現了一套徹底知足不可變要      求的數據結構和庫:Swiftz。堅持使用let和swiftz提供的數據結構來操做,就能夠實現「純函數式」編程。數組

     不變性有諸多好處安全

  • 更高層次的抽象。程序員能夠以更接近數學的方式思考問題。數據結構

  • 更容易理解的代碼。因爲不存在反作用,不管多少次執行,相同的輸入就意味着相同的輸出。純函數比有可變狀態的函數和對象理解起來要容易簡單得多。你無需再擔憂對象的某個狀態的改變,會對它的某個行爲(函數)產生影響。多線程

  • 線程安全的代碼。這意味着多線程環境下,運行代碼沒有同步問題。它們也不可能由於異常的發生而處於沒法預測的狀態中。

惰性求值

惰性計算是函數式編程語言的一個特性。惰性計算的表達式不在它被綁定到變量以後就當即求值,而是在該值被取用的時候求值。惰性計算有以下優勢。

  • 首先,你能夠用它們來建立無限序列這樣一種數據類型。由於直到須要時纔會計算值,這樣就可使用惰性集合模擬無限序列。
  • 第二,減小了存儲空間。由於在真正須要時纔會發生計算。因此,節約了沒必要要的存儲空間。
  • 第三,減小計算量,產生更高效的代碼。由於在真正須要時纔會發生計算。因此,節約那部分沒有使用到的值的計算時間。例如,尋找數組中第一個符合某個條件的值。找到了以後,數組裏該值以後的值均可以沒必要計算了。
func doSomeWork(optional:Int?,defaultValue:Int)->Int{
    if let opt = optional{
        return opt
    }else{
        return defaultValue
    }
}

func doSomeWorkNew(optional:Int?, defaultValue:()->Int)->Int{
    
    if let opt = optional{
        return opt
    }else{
        return defaultValue()
    }
}

let value:Int? = 1
doSomeWork(value, (2+5))
doSomeWorkNew(value, { () -> Int in
    return 2+5
})

上面的代碼能夠感受到惰性求值的好處。

swift也提供了支持惰性求值的語法:下面展現了將默認是嚴格求值的數組變爲惰性序列:

let r = 1...3
let seq = lazy(r).map {
    (i: Int) -> Int in
    println("mapping \(i)")
    return i * 2
}

for i in seq {
    println(i)
}

 

      Swift對函數式編程的支持,使得程序員多了一種選擇。Swift並不強迫程序員必定要以面向對象的方法思惟。在場景合適的狀況下,程序員能夠選擇使用函數式風格編寫代碼。若是確實是合適的場景,就可以改善生產力。現實的選擇是支持面向對象編程的同時,提供函數式的支持。這樣,在大部分面向對象遊刃有餘的地方,仍然可使用面向對象的方法。而在適合函數式編程的地方,而你又擁有函數式編程的思惟和能力時,還能夠採用函數式的編程方法改善生產力。

 

接下來的系列文章中我將以《Functional Programing in Swift》這本書,來一塊兒學習swift的函數式編程。

相關文章
相關標籤/搜索