草繪利弊細胞
為了更好地理解 conses 和列表的語義,經常使用這種結構的圖形表示。cons 單元通常用兩個接觸的盒子表示,它們包含指向 car
和 cdr
值的兩個箭頭,或者直接指向值。例如,結果:
(cons 1 2)
;; -> (1 . 2)
可以用以下圖紙之一表示:
請注意,這些表示純粹是概念性的,並不表示值包含在單元格中或從單元格指向的事實 :通常這取決於實現,值的型別,優化級別等在本例的其餘部分中,我們將使用第一種繪圖,這是一種更常用的繪圖。
所以,例如:
(cons 1 (cons 2 (cons 3 4))) ; improper `dotted` list
;; -> (1 2 3 . 4)
表示為:
而:
(cons 1 (cons 2 (cons 3 (cons 4 nil)))) ;; proper list, equivalent to: (list 1 2 3 4)
;; -> (1 2 3 4)
表示為:
這是一個樹狀結構:
(cons (cons 1 2) (cons 3 4))
;; -> ((1 . 2) 3 . 4) ; note the printing as an improper list
最後一個示例顯示了這種表示法如何幫助我們理解語言的重要語義方面。首先,我們編寫一個類似於前一個的表示式:
(cons (cons 1 2) (cons 1 2))
;; -> ((1 . 2) 1 . 2)
可以通常的方式表示為:
然後,我們編寫一個不同的表示式,這顯然與前一個表示式相同,這似乎通過結果的列印表示來確認:
(let ((cell-a (cons 1 2)))
(cons cell-a cell-a))
;; -> ((1 . 2) 1 . 2)
但是,如果我們繪製該圖中,我們可以看到的是,表達的語義是不同的,因為相同的細胞是值兩者的 car
部和外 cons
的 cdr
部分(這是,cell-a
被的共享 ):
並且可以通過以下測試驗證兩個結果的語義在語言級別上實際上不同的事實:
(let ((c1 (cons (cons 1 2) (cons 1 2)))
(c2 (let ((cell-a (cons 1 2)))
(cons cell-a cell-a))))
(list (eq (car c1) (cdr c1))
(eq (car c2) (cdr c2)))
;; -> (NIL T)
第一個 eq
是*假的,因為 c1
的 car
和 cdr
在結構上相等( equal
確實如此 ),但不是相同(即相同的共享結構),而在第二次測試中結果是真的,*因為 c2
的 car
和 cdr
是相同的,即它們是相同的結構。