[英]How does Lisp's getf work for a list?
所以我有一段簡單的代碼:
(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)
為什么會發生這種情況,我該如何解決?
還有其他一些答案可以解決這個問題,但我認為有時候舉個例子是有用的。 重要的部分是符號具有包,並且(除了一些警告),在一個包中具有給定名稱的符號與在另一個包中具有相同名稱的符號不同。
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產生: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
(getf L :z)
在當前綁定到L
的列表中找到與符號:z
關聯的值:
:z
與符號z
幾乎沒有關系 :z
與當前綁定到z
的值無關 至少,請閱讀《大程序設計:包和符號》 (以及為什么不讀整本書)。
您不能將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
的值(在當前包中)決不會影響: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)
因為列表和符號本質上是不可互換。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.