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

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

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

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

我們都知道:

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

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

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

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


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

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

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

聰明的人們想到了一個辦法,如果函數(shù) A 拿到參數(shù) ① 之后能夠返回另一個函數(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īng)關(guān)系,所以不管呼叫 longLiveSeniorFunc(1) 多少次結(jié)果都是一樣。所以,每次 +1 前應(yīng)該重新定義 longLiveSeniorFunc,使用最新的 senior。此處省略。)

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

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

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

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


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

而這個 plusAny 函數(shù),就是一個閉包。因為它返回了一個函數(shù),且此函數(shù)“包”進了 plusAny 函數(shù)作用域里的一個本地變量 senior,并且可以在其存續(xù)期間持續(xù)使用這個變量。

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

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

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


更新
-----

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

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

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

讀取 a,保存;

讀取 b,計算 a + b;

返回結(jié)果。


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

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

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

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

那么,為什么要這么嚴格而極致地來定義這樣一套體系?因為先行者們想發(fā)明一套通用的、可計算任意算式的計算機架構(gòu),比如與 Lambda Calculus 同時期的圖靈機。

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


Notes de version

Entrées populaires