计算机程序的构造和解释(Lec5b:计算对象) ,整個影片都很值得看,但這篇要說的是從 46:35左右開始講的,後面參雜了一點 lec6a。
最近開始學Clojure,所以內容中操作的部分會用clojure來呈現
任何的一個object的最小單位就是一個pair,而如何組成pair這個data structure呢,就是利用 cons , (cons x y)
就是一個pair。
對於任何的 x, y
(car (cons x y)) = x
(cdr (cons x y)) = y
但其實上述定義並沒有闡述,到底cons是否有像人一樣的身份(identity)?
就上述的定義來說,其實是一種抽象,cons包含兩個參數,如果兩個cons包含的參數是一樣的,那這兩個cons就是一樣的。
上述定義就不完整了,因為如果我想修改兩個包含一樣參數cons的car,那兩個cons都同時會被我修改嗎?
如果兩個cons代表的是數學,那其實沒差,就算是兩個一樣的 3/4,就還是3/4,變成同把兩個3/4變成1/4,反正就是1/4,並沒有所謂 身份 的區別,
但物件導向的世界中,我們描述的是真實的世界,是有 身份 的,改變car可能就像是做變性手術一樣der。
(def a (cons 1 2))
這是說我在一個環境裡面,創造了一個名為 a 的 pair,這個pair裡面包含兩個指針一個指向1,一個指向2。
接下來,我又定義了一個 b (def b (cons a a))
那 b 這個pair指向的兩個a,是同一個a嗎? 且現在呼叫 a 的方式有三種 a, (car b), (cdr b) ,哪個才是真正的呢?
而現在我用了 賦值去改 car b (set-car! (car b) 3)
,原本存在 a 的 1被改成3了。
現在如果再呼叫 (car a) 回傳的會是 3,儘管一開始我們定義的 (car a) 是1。
非預期的共享,是大型系統的bug來源,透過給object一個身份 ,給它一個別名互相共享,是有蠻多方便,但也相對付出了代價。
(defn cus-cons [x y] (fn [fc] (fc x y)))
(defn cus-car [fc2] (fc2 (fn [a d] a)))
(cus-car (cus-cons 1 2)) ;=> 1
演繹一下這個神奇的程序
(fn [fc] fc 1 2)
((fn [fc] fc 1 2) (fn [a d] a))
, (fn [a d] a)
被當成參數代換掉 fc((fn [a b] a) 1 2)
,回傳值就是1了,超級神奇吧!稍微修改一下 church的算式
(defn cus-cons
[x y]
(fn [fc]
(fc x
y
(fn [n] (let [x n]))
(fn [n] (let [y n])))))
(defn cus-car [fc2] (fc2 (fn [a d sa sd] a)))
(defn cus-cbr [fc2] (fc2 (fn [a d sa sd] d)))
(defn cus-set-car! [fc2 x2] (fc2 (fn [a d sa sd] (sa x2))))
(defn cus-set-cdr! [fc2 y2] (fc2 (fn [a d sa sd] (sd y2))))
在cons的地方,新增兩個lambda參數作為修改的認證用,這個set理論上是可行的,而有了一個set,就可以做千千萬萬個set了
Lambda這個方式,完全是用function來完成 cons car cdr,並沒有存在任何一的地方,真的很有趣啊,之後一定要來看一下 這個傳說中的 Alonzo church lambda calculus!!!
回到賦值與state的討論,當開始任意使用賦值,以下問題便開始產生
有這麼多問題產生,為何要這麼做?
因為想構造 模塊化 modularity的系統,對應真實世界的模型,而也許我們對於真實世界有些誤解,也許時間只是一個幻覺,並不會改變什麼,也許不用把時間切成一點一點分開看待,更宏觀的來看成一個"時空"的路徑。
如何解決:回到數位電路模擬器,可以以訊號處理的角度,而不是以單一時序的角度來看,如何做呢? 請繼續看下去