函式式程式設計(四) 函式組合 函子

2021-10-13 20:56:04 字數 3832 閱讀 8407

純函式和柯里化很容易寫出洋蔥** h(g(f(x))),就是乙個函式鑲嵌另乙個函式,多重組合,最終實現我們想要的功能,就像下面這個洋蔥一樣:

函式組合,就是利用多個函式,把細粒度的函式重新組合生成乙個新的函式,從而實現我們想要的邏輯。

比如:獲取陣列的最後乙個元素再轉換成大寫字母, .toupper(.first(_.reverse(array)))

管道

下面這張圖表示程式中使用函式處理資料的過程,給 fn 函式輸入引數 a,返回結果 b。可以想想 a 資料通過乙個管道得到了 b 資料:

當 fn 函式比較複雜的時候,我們可以把函式 fn 拆分成多個小函式,此時多了中間運算過程產生的 m 和 n。

下面這張圖中可以想象成把 fn 這個管道拆分成了3個管道 f1, f2, f3,資料 a 通過管道 f3 得到結果 m,m再通過管道 f2 得到結果 n,n 通過管道 f1 得到最終結果 b:

**形式簡單表現為:

fn =

compose

(f1, f2, f3)

b =fn

(a)

如果乙個函式要經過多個函式處理才能得到最終值,這個時候可以把中間過程的函式合併成乙個函式。

函式就像是資料的管道,函式組合就是把這些管道連線起來,讓資料穿過多個管道形成最終結果。

函式組合預設是從右到左執行:

// 組合函式 

function

compose

(f, g)

}// 取首值

function

first

(arr)

// 反轉

function

reverse

(arr)

// 從右到左執行

let last =

compose

(first, reverse)

console.

log(

last([

1,2,

3,4]

))

函式的組合要滿足結合律 (associativity):我們既可以把 g 和 h 組合,還可以把 f 和 g 組合,結果都是一樣的:

// 結合律(associativity) 

let f =

compose

(f, g, h)

let associative =

compose

(compose

(f, g)

, h)

==compose

(f,compose

(g, h)

)// true

到目前為止已經已經學習了函式式程式設計的一些基礎,但是我們還沒有演示在函式式程式設計中如何把***控制在可控的範圍內、異常處理、非同步操作等。

什麼是 functor

容器:包含值和值的變形關係(這個變形關係就是函式)。

函子:是乙個特殊的容器,通過乙個普通的物件來實現,該物件具有 map 方法,map 方法可以執行乙個函式對值進行處理(變形關係)。

functor 函子

// 乙個容器,包裹乙個值 

class

container

constructor

(value)

// map 方法,傳入變形關係,將容器裡的每乙個值對映到另乙個容器

map(fn)

}// 測試

container.of(

3).map

(x => x +2)

.map

(x => x * x)

總結函式式程式設計的運算不直接操作值,而是由函子完成; 函子就是乙個實現了 map 契約的物件;

我們可以把函子想象成乙個盒子,這個盒子裡封裝了乙個值;

想要處理盒子中的值,我們需要給盒子的 map方法傳遞乙個處理值的函式(純函式),由這個函式來對值進行處理;

最終 map 方法返回乙個包含新值的盒子(函子)。

在 functor 中如果我們傳入 null 或 undefined:

// 值如果不小心傳入了空值(***) 

container.of(

null).

map(x => x.

touppercase()

)// typeerror: cannot read property 'touppercase' of null

對錯誤進行處理,這就需要用到maybe函子了。

maybe 函子

我們在程式設計的過程中可能會遇到很多錯誤,需要對這些錯誤做相應的處理;

maybe 函子的作用就是可以對外部的空值情況做處理(控制***在允許的範圍)。

class

maybe

constructor

(value)

// 如果對空值變形的話直接返回 值為 null 的函子

map(fn)

isnothing()

}// 傳入具體值

maybe.of(

'hello world').

map(x => x.

touppercase()

)// 傳入 null 的情況

maybe.of(

null).

map(x => x.

touppercase()

)// => maybe

maybe 還是有個問題,就是我們很難確認是哪一步產生的空值問題,如下例:

maybe.of(

'hello world').

map(x => x.

touppercase()

).map(x =>

null).

map(x => x.

split

(' '))

// => maybe

either 函子either 兩者中的任何乙個,類似於 if…else…的處理,異常會讓函式變的不純,either 函子可以用來做異常處理:

class

left

constructor

(value)

map(fn)

}class

right

constructor

(value)

map(fn)

}

either 用來處理異常

function

parsejson

(json)

catch(e

));}

}let r =

parsejson(''

).map(x => x.name.

touppercase()

)console.

log(r)

函子的思想,還需多多體會和應用鍛鍊。

Js ES6函式式程式設計 函子

在正式學習函子之前,我會先丟擲乙個問題,先用普通的方式解決,然後轉換為用函子解決,這能幫助我們更好的理解函子。同時,這也是我想說的,在我們學習乙個新的知識點前,首先必須清楚為什麼會有它,或者說它是為了解決什麼問題而生的,這也是我們學習新知識後能夠快速達到學以致用的最有效方法,不然很容易被遺忘。fun...

python函式式程式設計模式 python函式式程式設計

1 callable內建函式判斷乙個名字是否為乙個可呼叫函式 import math x 1 y math.sqrt callable x false callable y true 2 記錄函式 文件字串 def square x calculates the square of number x...

python函式式程式設計模式 Python函式式程式設計

函式式程式設計就是一種抽象程度很高的程式設計正規化,純粹的函式式程式語言編寫的函式沒有變數,因此,任意乙個函式,只要輸入是確定的,輸出就是確定的,這種純函式我們稱之為沒有 而允許使用變數的程式語言,由於函式內部的變數狀態不確定,同樣的輸入,可能得到不同的輸出,因此,這種函式是有 的。函式式程式設計的...