javascript
javascript 基础下
五、函數式
這個可不是JavaScript的發明,它的發明人已經死了,而他的這個發明還在困擾著我們……如同愛迪生的燈
泡還在照耀著我們。
其實函數式語言很簡單,它就是一種與命令式語言同樣“完備”的語言實現方案。由于它的基礎思想與命令
式——如果你不想用這個難于理解的名詞,那就把它換成C,或者Delphi好了——語言完全不同,所以大多數
情況下,它也與這些傳統的、通用的、商業化的語言格格不入。
而事實上,你天天都在用它。
下面這行代碼,就充滿了函數式語言的思想:
a + b
是嗎?真的,如果你把那個“+”號看成一個函數,就完全一樣了。事實上,所謂函數(function),就是一個
執行過程、一段運算、一個功能入口……也就是說,代碼中的某個東西,要么它是數據,要么它是運算。而如
果它是運算,你就可以把它看成“函數”。上面這行代碼——表達式中,a和b顯然是數據,而+號則是對之進
行操作的運算,所以它自然可以看成一個“功能、過程或運算”。所以……操作兩個數求和的“函數”可以寫
成這樣:
func_add(a, b)
或者這樣:
(+ a b)
所有這些,只是文字上的標記法不同而已。就好象我說這個符號是“jia”,而你非得說它是“暗得”,另一個
人卻非要讀作“a-d-d”。有什么不同嗎?沒有。
所有程序員天天都在寫語句,寫表達式,與運算邏輯。大家都知道這些東西都可以寫在一個……嗯……無比巨
大的函數里,或者分在無數個小的、看起來很漂亮的函數里。當所有這些函數一個又一個連續起來運算時,它
就成了“函數式語言”。所以稱為“函數式語言的祖老爺爺”的LISP就是這樣“把函數運算連起來”的語言:
?(defun subst (x y z)
?? (cond ((atom z)
????????? (cond ((eq z y) x)
??????????????? ('t z)))
???????? ('t (cons (subst x y (car z))
?????????????????? (subst x y (cdr z))))))
有人認為它是丑陋的意大利面條,也有人認為它是最簡潔的語言。Oh,隨你,了解了就好了,管它象什么尼。
由于函數式語言只有連續執行的函數——所以它沒有了“語句”而又必須實現邏輯上的完整性。簡單地說,他
需要在連續執行的過程中實現“順序、分支與循環”三個基本邏輯。函數式的解決之道,是用三元條件運算來
代替if/then/else,也就下面的代碼:
if a then b else c
// 相當于
a ? b : c
另外,就是用遞歸(函數調函數)來實現循環。考慮到遞歸函數調用中會導致棧溢出(Stack overflow at ...),
所以函數式語言就提出了“尾遞歸”,也就是在書寫代碼是“確保”僅只在函數內的最后一個運算中遞歸調用。
這樣一來,這個遞歸調用就不需要保留棧了——因為再沒有后續運算了,因此就能被優化成一行不需要返回的
jmp匯編指令。
世界真美好,所謂函數式不過是一堆運算入口,以及jmp、jmp、jmp。但,但是,難道不是嗎——這塊CPU?
六、更高級的函數式(1)
其實世界并不美好。
如果一塊CPU死躺在那里,它也就只有順序呀、分支啦、循環之類的指令在里頭。但是當它運行起來,就得有一
個時鐘在滴嗒…滴嗒…如果是多核的,還會同時有好幾個這樣的東東在滴嗒著。
這就是問題,世界原本不是單一時序,也不是守序的。所以會有并發,會有中斷,也會有異常。函數式語言應
該自己應該像意大利面條一樣無限延展開去,那么是不是有多個滴嗒時就該有多根意大利面條呢?但,這種情
況下還叫意大利面條嗎?
函數式里的解決方案叫延續(Continuation)和結點。延續是停止當前轉到另一處、然后再返回來;而結點則確
保一個位置上的代碼是獨立完備的,與另一個結點無關。在函數式語言中,多個結點就象平行宇宙,大多數情
況下它們是互相透明的,如果它們要發生聯系,得需要極其巨大的能量,以及……一個蟲洞。
多個結點的問題我們不需要深究,多個空間下的訪問帶來的時空問題,是天體學家以及時空多維理論家們研究
的問題,我們只需要知道:如果你希望多個結點之間存在交叉的訪問關系,那么世界/宇宙會因此毀滅。這樣類
似的說明寫在ErLang這類天生支持多個宇宙的語言的白皮書、參考手冊以及宇航員日常指南之中。如果你要窮
究其根源,并且認為自己已經能明確了解300個以上的高等數字、物理學和天體學術語,地么下面有一份面向程
序員的入口指引,不妨從這里開始:
http://www.blogjava.net/canonical/archive/2007/12/05/165664.html
延續是解決狀態問題的方法之一。簡單說來,有時間就有狀態:有過去,現在和將來。對于過去,我們有歷史,
也就會因為過去發生了什么而決定現在發生什么,例如因為昨天喝高了小酒,所以今天只能吃稀粥;而現在也
就是明天的昨天,所以要為了明天能做什么而記錄下今天的狀態,例如今天已經吃了稀粥;至于明天,當然,
將要發生的事情很多,我們得一件一件地做好準備。
Oh,重要的就是這個“做好準備”了。這在計算機系統里叫:事件。或者叫計劃,或者叫突發。知道為什么我
們的PC機可以運行嗎?En...是因為有一個指令流水線在按照一個足夠微小的時間片去執行指令。對于運算系統
來說,這個定時發生的指令訪問行為,就是中斷。所以有一天一個朋友問我:如果執行邏輯只有順序、分支與
循環,那么流程系統中的觸發器算什么?我想了很久,無解。而現在來回答這個問題,就得把“時間”這個維
度加上,所謂突發、并發以及類似的東西,是時序概念下的邏輯。
好了,當我們“做好準備”,為了將來要觸發某個東西做準備的時候——簡單的說,就當是個時鐘處理程序好
了(在windows中它叫OnTimer,在瀏覽器中它叫setTimeout/setInterval),為了這個時候我們能夠在函數式
語言中做好一頓意大利面條,我們說明:“我們已經做好了準備”,以及“我們做好了怎樣的準備”。而按照
函數式的基本原則,一個函數是與狀態無關的,它與“將來”這樣一個時序無關。這,變成了一個矛盾。
事實上開始我們已經與這個矛盾正面沖突了一次,這就是“循環”。因為循環需要一個狀態量來指示循環進度,
這個“進度”就是時序相關的。而函數式使用了“遞歸”來解決它,也就是通過遞歸函數的參數來傳遞這個進
度。在“遞歸參數”——這個界面的兩邊,函數式都是時序無關的。由此帶來的問題就是棧溢出,解決方法則
是尾遞歸;又由此帶來的問題就是編程復雜性,以及能否證明尾遞歸能替代所有遞歸;解決方案是……溫伯格
說得沒錯,所有解決問題的方法都會帶來新的問題。Oh...又是溫伯格。
現在,我們明確的需要“更多的狀態”了,因為我們已經將系統運行一個或是多個的時序里——也就CPU。即使
我們有結點,而且保證“沒有蟲洞”,那么我們也需要解決一個CPU中的過去、現在與將來的問題。
函數式的仙家們說了兩個字:持續。簡單啊,就是把為過去、現在的狀態,和為將來的準備作為函數的參數傳過
去。看起來,“現在”立即就要爆炸了,因為既要包括過去的、現在的狀態以及變化,還要包括將來的運算。于
是新的解決方案是:若要現在不爆炸,"持續"的界面上不要發生運算就好了。
運算由“將來”根據“過去”的數據做決策,這就是持續。支持它的函數式特性,就是在惰性求值。簡單的說,
function f(x, c) {
? ...
? c(x);
}
f(data, f);
由于在傳送界面f()上,c本身是不求值的,所以爆炸會發生在/不會發生都是在將來c(x)進行運算的時候。如果
宇宙的熵有極限,那么這個極限也是在末可知的將來。而且,在末可知的將來,也有可能回扭曲回現在。這就是
持續的兩個原則:
--------------------
一個成功持續之后,是一個新的持續(或過程)
一個失敗持續將回到上一個選擇點
--------------------
正是因為有持續的狀態,且這個狀態及持續本身都是通過函數參數傳遞的,所以,“回到選擇點”只是將來自身
的一個決擇,與現在的狀態是無關的。
七、更高級的函數式(2)
無論如何,種種函數式的復雜性,確實是在編程范型中保持一種自我的純粹性而存在的。例如生成器(產生器)
這個問題,由于一批數據的產生之間是有關系的(例如增量),而產生過程是時序相關的(不總是在一次調用中
得到全部的數據),因此函數式語言定義了一個“生成器”這樣的函數概念。我們可以在生成器中定義一個yield,
這個返回就是“將來”回到這個“現在”的一個蟲洞。通過這個蟲洞,我們可以拿到一個時序相關的數據。下面
就是這樣的一個例子(mozilla上的斐波那契數列示例):
<!-- for firefox 3 -->
<script type="application/javascript;version=1.7">
function fib() {
? var i = 0, j = 1;
? while (true) {
??? yield i;??????? //<-蟲洞在這里
??? var t = i;
??? i = j;
??? j += t;
? }
}
var g = fib();
a = g.next();
b = g.next();
c = g.next();
// ...
// .. 三天以后(或一個循環以后),某時空旅行家想回到fib里去看看
z = g.next();
// 呵,原來是值“2”
alert(z);
</script>
八、結語
好象,好象這篇《無廢話》有很多廢話……哈哈,玩笑啦,真的全無廢話,還是活人能看的木?
真的那么想讀無廢話,你應該去讀大學教材了。或者,這里還有一本《JavaScirpt語言精髓與編程實踐》。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/aimingoo/archive/2008/10/06/3022409.aspx
轉載于:https://www.cnblogs.com/dearamy/archive/2010/03/25/1694935.html
總結
以上是生活随笔為你收集整理的javascript 基础下的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 博士生与民工的笑话
- 下一篇: [你必须知道的css系列]第一回:丰富的