【SICP歸納】6 副作用與環境模型

nomasp發表於2015-03-28

雖說叫做副作用顯得不太好聽,但在Lisp中副作用還是非常重要的。而相對於所有狀態都必須顯式地操作和傳遞額外引數的方式,如果引進賦值和將狀態隱藏在區域性變數中,那麼就可以用更加模組化的方式來構造系統。

正如你所知道的,不用任何賦值的程式設計稱為函式式程式設計。相反,廣泛採用賦值的程式設計稱為命令式程式設計。在C等命令式程式設計語言中,我們往往都要仔細考慮變數賦值的順序,尤其是在迴圈中,但在函式式程式設計中這類問題根本不會出現。

(define x 1)
(define (add-x y)
   (set! x (1+ x))
   (+ x y))
(add-x 3)
5
(add-x 3)
6

在這裡我們看到同一個表示式卻會導致兩種不同的結果,而這一切都取決於時間。

我們常用define來定義一個為定義的變數、函式等等,而不用其來做修改的操作。set!則來完成修改這一工作。經常用到的let實際上是一個過程呼叫的語法糖衣。用define定義一個符號,也就是在當前環境框架裡建立一個約束,並賦予這個符號指定的值。

(let ((var1 e1) (var2 e2))
  e3)=>
((lambda (var1 var2)
        e3)
 e1
 e2)

在前面的代換模型中,我們是這樣求組合式的:
1)求值該組合式的各個子表示式
2)將作為最左子表示式(運算子)的值的那個過程應用於相應的實際引數,所謂實際引數也就是其他子表示式(運算物件)的值。
而在環境模型中,第二步就有所差異了:
1)求值該組合式的各個子表示式
2)將運算子子表示式的值應用於運算物件子表示式的值。

在將一個過程應用於一組實際引數時,將會建立起一個新環境,其中包含了將所有形式引數約束與對應的實際引數的框架,該框架的外圍環境就是所用的那個過程的環境。

書中這部分可謂歸納的非常好,過程應用的環境模型的兩條規則:
1)將一個過程物件應用於一集實際引數,將構造出一個新框架,其中將過程的形式引數約束到呼叫時的實際引數,而後在構造起的這一新環境的上下文中求值過程體。這個新框架的外圍環境就是作為被應用的那個過程物件的一部分的環境。
2)相對於一個給定環境求值一個lambda表示式,將建立起一個過程物件,這個過程物件是一個序對,由該lambda表示式的正文和一個指向環境的指標組成,這一指標指向的就是建立這個過程物件時的環境。

現在我們已經有能力去使用獨立的本地狀態和物件模型,也會進行一些比較複雜的程式設計。我們活在物理世界中,也以物理世界的方式去思考,這正是由這些構成了整個世界。為什麼物理學家、天文學家等在尋找系外生命時要以地球的指數為參照,比如說溫度、大氣、土壤、公轉和自轉等,因為有些事物是共通的。之前看到過一個老外寫的書,當時對軟體這個專業還沒有多少認識,書也全是理論比較晦澀因此沒能看多久,不過記得作者的一個比喻非常好。其認為寫一個軟體就像設計一座建築,每部分有組織的組合拼湊在一起。

《計算機程式的構造和解釋》雖然已經有了三十多年的歷史,卻依舊格外而不落伍的原因便是其是在講解如何去構建一座建築。它會告訴我們建築的每個部分都有哪些功能和優缺點,這個柱子該放在哪裡撐著,兩層樓之間該怎樣結合等等。而各自語言就像修建這個建築的各種材料,比如鋼鐵和木材等。其並沒有太注意去講解語言的語法,一來這是介紹“建築材料”的書籍需要做的,二來Lisp的語法也不太繁雜。

在我們的腦海中有對這個世界的認識以及一個不斷構建中的模型,當我們在編寫軟體時,這些模型也即體現於計算機中。我們想要做的無非就是讓這兩者之間進行通訊。這就帶來了模組化,如果我們真的相信世界就是由這樣的小片段所組成,那麼我們也同樣可以將這種思想應用於我們所構造的模型中,世界上的這些事物也將能夠繼承這種模組化設計進入我們的程式之中。



感謝訪問,希望對您有所幫助。 歡迎關注或收藏、評論或點贊。


為使本文得到斧正和提問,轉載請註明出處:
http://blog.csdn.net/nomasp


相關文章