亚洲国产日韩欧美一区二区三区,精品亚洲国产成人av在线,国产99视频精品免视看7,99国产精品久久久久久久成人热,欧美日韩亚洲国产综合乱

設(shè)計(jì)閉包(Closure)的初衷

asal 2016-11-01 14:33:09 565
abstrak:閉包是函數(shù)式編程及其核心思想“Lambda 計(jì)算法”(Lambda Calculus)的必備基本設(shè)定。我們都知道:函數(shù)式編程有一個(gè)特點(diǎn),就是所有操作都用可計(jì)算的函數(shù)(computable function,下簡稱“函數(shù)”)來體現(xiàn)。函數(shù)的兩個(gè)特點(diǎn),就是每個(gè)函數(shù)都有一個(gè)輸入值,一個(gè)輸出值。函數(shù)還有一個(gè)定律,就是給定一個(gè)確定的輸入值,總能得到一個(gè)確定的輸出值,即輸入輸出有嚴(yán)格的一一對(duì)應(yīng)關(guān)系。(當(dāng)然還有無

閉包是函數(shù)式編程及其核心思想“Lambda 計(jì)算法”(Lambda Calculus)的必備基本設(shè)定。

我們都知道:

函數(shù)式編程有一個(gè)特點(diǎn),就是所有操作都用可計(jì)算的函數(shù)(computable function,下簡稱“函數(shù)”)來體現(xiàn)。

函數(shù)的兩個(gè)特點(diǎn),就是每個(gè)函數(shù)都有一個(gè)輸入值,一個(gè)輸出值。

函數(shù)還有一個(gè)定律,就是給定一個(gè)確定的輸入值,總能得到一個(gè)確定的輸出值,即輸入輸出有嚴(yán)格的一一對(duì)應(yīng)關(guān)系。

(當(dāng)然還有無副作用之類,此處不論。)


那么,在這樣的限制條件下,請(qǐng)問,“加法”的函數(shù)怎么寫?

function plus(senior) {
    return senior + 1;}

是,這倒是 +1s 了,但是怎么加任意數(shù)值呢?加法的定義是 a + b,兩個(gè)參數(shù)。記住,函數(shù)只能有一個(gè)輸入,一個(gè)輸出。

聰明的人們想到了一個(gè)辦法,如果函數(shù) A 拿到參數(shù) ① 之后能夠返回另一個(gè)函數(shù) B,而函數(shù) B 拿到參數(shù) ②,再把參數(shù) ① 和 ② 糅合起來就可以了。

function plusAny(senior) {
   return function(second) {
        return senior + second;
   }}/* usage */var senior = 2838240000;var longLiveSeniorFunc = plusAny(senior);longLiveSeniorFunc(1);     // +1slongLiveSeniorFunc(3600);  // +1hlongLiveSeniorFunc(86400); // +1d

(注意輸入輸出有嚴(yán)格對(duì)應(yīng)關(guān)系,所以不管呼叫 longLiveSeniorFunc(1) 多少次結(jié)果都是一樣。所以,每次 +1 前應(yīng)該重新定義 longLiveSeniorFunc,使用最新的 senior。此處省略。)

有了此法,不管多少參數(shù),都可以用此法來轉(zhuǎn)換成一個(gè)參數(shù)。

不過等一下,這需要我們做一些設(shè)定:

首先,認(rèn)可“函數(shù)”和“數(shù)字”、“字符”等等一樣,是一種“值”(value)

然后,認(rèn)可“函數(shù)”可以和其他值一樣,可以賦給一個(gè)變量,返回,或者當(dāng)做參數(shù)來傳遞


這意味著函數(shù)享有其他“值”的便利,可稱之為一個(gè)語言的“一等公民”(first-class citizen)。不過,這時(shí)候這個(gè)函數(shù)還只是一個(gè)匿名函數(shù)(anonymous function),還不能稱之為閉包。

而這個(gè) plusAny 函數(shù),就是一個(gè)閉包。因?yàn)樗祷亓艘粋€(gè)函數(shù),且此函數(shù)“包”進(jìn)了 plusAny 函數(shù)作用域里的一個(gè)本地變量 senior,并且可以在其存續(xù)期間持續(xù)使用這個(gè)變量。

那么,為什么 A 函數(shù)內(nèi)部定義的函數(shù)能訪問 A 函數(shù)作用域的變量?為什么要這樣設(shè)定?很簡單,因?yàn)椴贿@樣設(shè)定,函數(shù)式編程就連加法都沒法定義啊……

所以,閉包是函數(shù)式的基本配備。

當(dāng)然,函數(shù)入魔的朋友們也搞出了很多濫用的幺蛾子,那又是后話了……


更新
-----

關(guān)于函數(shù)為什么只能有一個(gè)參數(shù)的問題,試分析一下。

第一是抽象。既然所有“多參數(shù)函數(shù)”都可以抽象成一個(gè)高級(jí)的“單參數(shù)函數(shù)”(用上面的方法),那么意味著“多參數(shù)函數(shù)”本身是有信息冗余的。這個(gè)抽象的過程就像是拆掉分子分母的公約數(shù)一樣,去掉了這個(gè)冗余。

第二是計(jì)算。我們想象一下任何一種“計(jì)算機(jī)器”,它要做一個(gè)最簡單的加法,那么它需要:

讀取 a,保存;

讀取 b,計(jì)算 a + b;

返回結(jié)果。


那么可以看出,在第 1 步時(shí)如果這個(gè)機(jī)器暫停,那么實(shí)際上它保存了一個(gè)“狀態(tài)”(state),而沒有進(jìn)行任何“計(jì)算”。

如果把這個(gè)保存了某個(gè)狀態(tài)的機(jī)器視作是一個(gè)新的機(jī)器(在內(nèi)存里寫死了 a 值,等待 b 值做加法),那么新的機(jī)器才是真正在做“計(jì)算”。原來什么值都沒有保存的機(jī)器有沒有在做計(jì)算呢?我們不妨認(rèn)為它也在做“計(jì)算”,這個(gè)計(jì)算的參數(shù)則是 a 值,計(jì)算結(jié)果就是前面說的新機(jī)器。

如此,既確保了沒有信息冗余(嚴(yán)格說第 2 步還可以繼續(xù)拆),狀態(tài)被作為顯性的參數(shù)所捕捉,并且每一個(gè)步驟都是一次“計(jì)算”,且計(jì)算的結(jié)果和參數(shù)一一對(duì)應(yīng)。

換句話說,就是函數(shù)成了“無狀態(tài)”,它返回什么,完全且僅取決于你給它喂什么參數(shù)。只要你喂的參數(shù)不變,到世界末日它也會(huì)返回給你同樣的結(jié)果。這進(jìn)一步意味著這個(gè)函數(shù)是完全獨(dú)立的,可以獨(dú)立存在(比如抽成庫或者服務(wù)),可以很容易地替換(只需確保輸入輸出對(duì)應(yīng)關(guān)系),可以很容易地測(cè)試(只需檢查輸入輸出)。

那么,為什么要這么嚴(yán)格而極致地來定義這樣一套體系?因?yàn)橄刃姓邆兿氚l(fā)明一套通用的、可計(jì)算任意算式的計(jì)算機(jī)架構(gòu),比如與 Lambda Calculus 同時(shí)期的圖靈機(jī)。

了解了這些,就能領(lǐng)略函數(shù)式編程之美,并且可以用更批判的眼光看待各種編程語言,還會(huì)對(duì)架構(gòu)設(shè)計(jì),測(cè)試編寫等大小方面有各種好處。


Nota Keluaran

Penyertaan Popular