Lisp的getf如何为列表工作?

时间:2015-10-28 04:36:49

标签: list lisp common-lisp

所以我有一段简单的代码:

(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)

为什么会发生这种情况,我该如何解决?

4 个答案:

答案 0 :(得分:3)

还有一些其他答案可以解决这个问题,但我认为有时候一个例子很有用。重要的是,符号有和(除了一些警告)在一个包中具有给定名称的符号与在另一个包中具有相同名称的符号不是同一符号。

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

答案 1 :(得分:2)

(getf L :z)找到与当前绑定到:z的列表中的符号L相关联的值:

  • :z与符号z
  • 几乎没有任何关系
  • :z与当前绑定到z
  • 的值无关

至少,请阅读Programming in the Large: Packages and Symbols(以及为什么不是,全书)。

您无法将z绑定到a,并期望:z评估为:a。您可以做的是将z绑定到a并根据:a的当前值访问符号z。此外,符号: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。

答案 2 :(得分:1)

首先,getf适用于property list这是一种特殊的列表。函数lol也不使用变量z。它始终在属性列表中查找'(a) 关键字。如果你想参数化由lol查找的符号,你就不会传递一个列表((defun lol (z) (getf (list :a 1 :b 2 :c 3) z)) (lol :a) ; => 1 ),而是一个关键字。

ALTER SCHEMA SCHEMA_NAME DEFAULT COLLATE utf8_bin;

答案 3 :(得分:0)

这是因为(a)是一个列表,其头部包含名称为a的符号,在当前包中加密,:z是名称为{{1}的符号在z包中实习。绑定到keyword的值是偶然的,&#34;名为z的符号,在关键字包&#34;中实现。

从来没有绑定到符号: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,因为列表和符号基本上不可互换。