所以我有一個簡單的代碼:Lisp的getf如何爲列表工作?
(defun lol (z) (getf (list :a 1 :b 2 :c 3) :z))
當我啓動功能:
(lol '(a))
這給了我NIL而不是1.不是上述技術一樣:
(getf (list :a 1 :b 2 :c 3) :a)
爲什麼會發生這種情況,我該如何解決?
所以我有一個簡單的代碼:Lisp的getf如何爲列表工作?
(defun lol (z) (getf (list :a 1 :b 2 :c 3) :z))
當我啓動功能:
(lol '(a))
這給了我NIL而不是1.不是上述技術一樣:
(getf (list :a 1 :b 2 :c 3) :a)
爲什麼會發生這種情況,我該如何解決?
第一個getf在property list上工作,這是一種特殊的列表。此外,函數lol不使用變量z。它始終在屬性列表中查找:z
關鍵字。如果你想參數化按lol查找的符號,你不會傳遞一個列表('(a)
),而是一個關鍵字。
(defun lol (z)
(getf (list :a 1 :b 2 :c 3) z))
(lol :a) ; => 1
(getf L :z)
發現在當前綁定到L
列表相關的符號:z
值:
:z
與符號z
:z
幾乎沒有任何關係,與當前值無關綁定到z
至少,閱讀Programming in the Large: Packages and Symbols(以及爲什麼不是整本書)。
不能綁定z
到a
並期望:z
,以評估:a
。你所能做的就是將z
綁定到a
,並根據當前值z
訪問符號:a
。此外,符號:z
是一個關鍵字,不能用作局部變量。
(defun lol (z) (getf '(:a 1 :b 2 :c 3) z))
在上文中,局部變量z
將持有的值,這將被傳遞給調用getf
。
在此呼籲:
(lol '(a))
...局部變量z
勢必(a)
,恆定的列表,它的第一個元素是符號a
。如果在lol
中使用此值,則不會返回nil
以外的任何內容,因爲GETF
將在列表中搜索同一個相同的元素(如果需要,則使用相同的內存地址)。
GETF
應該用符號調用,因爲兩個發生的package:symbol
引用相同的數據結構(如哈希映射)。你必須調用它像這樣:
(lol 'symbol)
,或者因爲關鍵字評價自己:
(lol :symbol)
在你的情況,(lol :a)
將讓你1
這是因爲(a)
是在其頭部包含名稱爲a
的符號,在當前包中被執行,並且:z
是在keyword
包中被執行的名稱爲z
的符號。綁定到:z
的值是偶然的,「名稱爲z的符號,在關鍵字包中實現」。
這種情況絕不會出現符號z
(在當前包中)綁定的值影響:z
的值。
因此,不,(defun lol (z) (getf (list :a 1 :b 2 :c 3) :z))
定義了一個返回與(getf (list :a 1 :b 2 :c 3) :z)
相同的值的函數。要修復它,請將:z
替換爲z
,並調用(lol :a)
之類的函數,因爲列表和符號基本上是不可互換的。
還有其他一些答案涵蓋了這個問題,但我認爲有時候一個例子是有用的。重要的部分是符號有包和(一些注意事項)一個包中給定名稱的符號與另一個包中具有相同名稱的符號不是同一個符號。
CL-USER> (defparameter *plist* (list 'a 1 ':a 2))
*PLIST*
CL-USER> (first *plist*)
A
CL-USER> (third *plist*)
:A
CL-USER> (eql (first *plist*) (third *plist*))
NIL
CL-USER> (getf *plist* 'a)
1
CL-USER> (getf *plist* ':a)
2
現在,可能會使這一點在一開始迷惑的是,符號方式印刷並不總是顯示符號的完整包名。上述提示中的「CL-USER」表示當前包爲CL-USER包,因此該包中的符號或使用的符號不會顯示其包名稱。如果我們創建一個新的包,並切換到它,並打印*的plist *,我們可以看到這一點:
CL-USER> (defpackage #:temp)
#<PACKAGE "TEMP">
CL-USER> (in-package #:temp)
#<COMMON-LISP:PACKAGE "TEMP">
TEMP> cl-user::*plist*
(COMMON-LISP-USER::A 1 :A 2)
注意的* plist中的第一個元素*印有「COMMON-LISP -USER「(」CL-USER「是」COMMON-LISP-USER「的暱稱)。現在,符號:A以相同的方式打印。那是怎麼回事? Common Lisp有一個叫做「KEYWORD」的特殊軟件包,該軟件包中的符號稱爲關鍵字符號。他們幾乎像其他符號,除了他們都被綁定到自己(所以評估:產生:a,並且引用是沒有必要的),它們都是外部的,並且通常用一個冒號作爲它們的前綴。您可以寫關鍵詞詞首,不過,如果你想:
TEMP> 'keyword::a
:A
TEMP> 'keyword:b
:B
TEMP> keyword::c ; no need to quote
:C
TEMP> keyword:d
:D
所以,如果你想編寫一個函數,屬性列表指示器和檢索一些固定的屬性列表中的值,你倒是做這樣的事情(請注意,在屬性列表中的指標並不必須是符號,作爲最後一個例子展示):
(defun example (indicator)
(getf '(:a 1 :b 2 c 3 4 5) indicator))
CL-USER> (example :a) ; OR ':a OR keyword::A OR ...
1
CL-USER> (example keyword:b) ; OR ...
2
CL-USER> (example 'c) ; OR 'cl-user::c OR ...
3
CL-USER> (example 4) ; OR (+ 2 2) OR ...
5