簡體   English   中英

Lisp的getf如何用於列表?

[英]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。

首先,getf在屬性列表上工作,該屬性列表是一種特殊的列表。 同樣,函數lol也不使用變量z。 它總是在屬性列表中查找:z 關鍵字 如果要參數化由大聲笑查找的符號,則不會傳遞列表( '(a) )而是關鍵字。

(defun lol (z)
  (getf (list :a 1 :b 2 :c 3) z))

(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) 為了解決這個問題,更換:zz和調用函數一樣(lol :a)因為列表和符號本質上是不可互換。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM