最近初學swift,和oc比,發現語言更現代,也有了更多的特性。如何寫好swift**,也許,熟練使用新特性寫出更優秀的**,就是答案。今天先從大的方向談談swift中的程式設計正規化-函式式程式設計。主要還是讀了大佬帖子,寫寫自己的理解。
"函式式程式設計"是一種"程式設計正規化"(programming paradigm),也就是如何編寫程式的方**。
它屬於"結構化程式設計"的一種,主要思想是把運算過程盡量寫成一系列巢狀的函式呼叫。
它使**更像自然語言,告訴程式設計師要幹什麼,而不是怎麼幹,把怎麼幹的細節拆分到各個函式中。呼叫的地方邏輯清晰,便於debug。
舉例來說,現在有這樣乙個數學表示式:
(1 + 2) * 3 - 4
傳統的過程式程式設計,可能這樣寫:
var a = 1 + 2;var b = a * 3
;var c = b - 4;
函式式程式設計要求使用函式,我們可以把運算過程定義為不同的函式,然後寫成下面這樣:
var result = subtract(multiply(add(1,2), 3), 4);
這就是函式式程式設計。
**簡潔,開發快速
函式式程式設計大量使用函式,減少了**的重複,因此程式比較短,開發速度較快。
接近自然語言,易於理解
函式式程式設計的自由度很高,可以寫出很接近自然語言的**。我們把程式的邏輯分成了幾個函式,這樣一來,我們的**邏輯也會變得幾個小碎片,於是我們讀**時要考慮的上下文就少了很多,閱讀**也會更容易。 而把**邏輯封裝成了函式後,我們就相當於給每個相對獨立的程式邏輯取了個名字,於是**成了自解釋的。
前文曾經將表示式(1 + 2) * 3 - 4,寫成函式式語言:
subtract(multiply(add(1,2), 3), 4)
對它進行變形,不難得到另一種寫法:
add(1,2).multiply(3).subtract(4)
更方便的**管理
函式式程式設計不依賴、也不會改變外界的狀態,只要給定輸入引數,返回的結果必定相同。因此,每乙個函式都可以被看做獨立單元,很有利於進行單元測試(unit testing)和除錯(debugging),以及模組化組合。
易於"併發程式設計"
函式式程式設計不需要考慮"死鎖"(deadlock),因為它不修改變數,所以根本不存在"鎖"執行緒的問題。不必擔心乙個執行緒的資料,被另乙個執行緒修改,所以可以很放心地把工作分攤到多個執行緒,部署"併發程式設計"(concurrency)。
所謂"第一等公民"(first class),指的是函式與其他資料型別一樣,處於平等地位,可以賦值給其他變數,也可以作為引數,傳入另乙個函式,或者作為別的函式的返回值。
舉例來說,下面**中的print變數就是乙個函式,可以作為另乙個函式的引數。
var print =function(i);[1,2,3].foreach(print);
函式(function)這個名詞來自於數學,函式通過乙個給定的值,計算出另外乙個值,也就是上學時常見的f(x)。
在通常的理解中,下面**裡面,f1,f2,f3通常都被叫做函式:
//偽** 函式無入參,返回2
def f1(): return2//
函式有引數x,返回 x+1
def f2(int x): return x+1
//函式無入參,無返回值,列印hello world
def f3(): print("
hello world
")
複製**但實際上,函式(function)和procedure是有區別的: function 通過運算返回乙個值,而procedure只執行一段**,沒有返回值。 這一點對於後面的理解是非常有幫助的,首先要區分出二者。
再回到上面的**中,f1,f2,為function而f3為procedure。
pure:純的; 單純的; 純真的; 乾淨的 我們將滿足下面兩個條件的函式稱作pure function:
side effect
函式呼叫後不會對外部狀態產生影響,比如下面這段**中sum函式是no side effect的:
def sum(a,b): return a+b
產生side effect的函式長成什麼樣呢?其實經常會寫這樣的函式:
int sum = 0def plus(a,b)
plus函式除了計算引數之和以外,還改變了外部變數sum的值,我們plus這個函式產生了side effect。 常見的side effect
引用透明(referential transparency),指的是函式的執行不依賴於外部變數或"狀態",只依賴於輸入的引數,任何時候只要引數相同,引用函式所得到的返回值總是相同的。
有了前面的第三點和第四點,這點是很顯然的。其他型別的語言,函式的返回值往往與系統狀態有關,不同的狀態之下,返回值是不一樣的。這就叫"引用不透明",很不利於觀察和理解程式的行為。
先說兩個概念型的名詞:
高階函式(high order func),指可以將其他函式作為引數或者返回結果的函式。
一級函式(first class func),指可以出現在任何其他構件(比如變數)地方的函式。
map
map
一般用在集合型別,對集合裡的元素進行遍歷,函式體裡實現對每乙個元素的操作。
var arr = [1,3,2,4]let mapres =arr.map
// 執行結果:["no.1", "no.3", "no.2", "no.4"]
reduce
reduce(result)
一般用在集合型別,對集合裡的元素進行疊加處理,函式體裡傳兩個引數,第乙個是之前的疊加結果,第二個是當前元素,返回值是對當前元素疊加後的結果。
//對陣列裡的元素:奇數相加,偶數相乘
var arr = [1,3,2,4
]let reduceres = arr.reduce((0,1))
else}//
執行結果:(4,8)
filter
filter
一般用在集合型別,對集合裡的元素進行篩選。函式體裡實現篩選條件,返回 true 的元素通過篩選。
var arr = [1,3,2,4]let filterres =arr.filter
//執行結果:[2,4]
flatmap
首先先看下 swift 原始碼裡對集合陣列的map和flatmap的實現:
//sequence.swift
extension sequence }//
sequencealgorithms.swift.gyb
extension sequence
public func flatmap(_ transform: (element) -> s) ->[s.element] {}
}
前面我們已經知道,map是一種遍歷,而上面的**又顯示出來,flatmap有兩種過載的函式:
其中一種與map非常相似,差別只在閉包裡的返回值變成了可選型別。 另一種稍微有點不同,閉包傳入的是陣列,最後返回的是陣列的元素組成的集合。
//maplet arr = [1,2,nil,4,nil,5
]let arrres = arr.map //
結果為:[optional(1), optional(2), nil, optional(4), nil, optional(5)]
//flatmap
let brr = [1,2,nil,4,nil,5
]let brrres = brr.flatmap //
結果為:[1, 2, 4, 5]
let crr = [[1,2,4],[5,3,2
]]let ccres = crr.flatmap //
結果為:[1, 2, 4, 5, 3, 2]
let cdres = crr.flatmap
} //
結果為[1, 4, 16, 25, 9, 4]
//使用 map 實現的上面平鋪功能
let ceres = array(crr.map.joined()) //
同 ccres
let cfres = array(crr.map.joined()).map //
同 cdres
簡單理解為,flatmap可以將多維陣列平鋪,也還以過濾掉一維陣列中的nil元素。
map和flatmap不只在陣列中可以使用,對於 optional 型別也是可以進行操作的。先看下面這個例子:
let a: date? =date()let formatter =dateformatter()
formatter.datestyle =.medium
let c = a.map(formatter.string
(from:))
let d = a == nil ? nil : formatter.string(from: a!)
c 和 d 是兩種不同的寫法,c 寫法是不是更優雅一些?
Python之 函式式程式設計
f lambda x x 2 定義函式f x x 2 g lambda x,y x y 定義函式g x,y x y 假設有乙個列表a 1,2,3 要給列表中的每個元素都加2得到乙個新列表,利用列表解析,我們可以這樣寫 b i 2 for i in a 利用map函式我們可以這樣寫 b map lam...
JS 之 函式式程式設計
由若干個純函式 偏函式 柯里化函式組合成乙個新的函式,同時,形成資料傳遞。挑選了一系列所需要的函式,把他們組合在一起,可以實現公共合作的效果。示例 function combination x var arr combination add,spl,toupper 三個函式,三個函式的資料都是相關聯...
Python之函式式程式設計
1 map map 函式接收兩個引數,乙個是函式,乙個是iterable,map將傳入的函式依次作用到序列的每個元素,並把結果作為新的iterator返回。def f x return x x r map f,1,2,3,4,5,6,7,8,9 print list r 1,4,9,16,25,36...