在 lisp 中比较数字和列表对象
Comparing a number and a list object in lisp
我是 lisp 的新手,如果提出这个问题,我深表歉意。
我有一个列表:
(set ‘inventory ‘(parts
((item 1001) (shoes (color brown) (size 10) (cost 20)))
((item 2011) (skirt (color blue) (size 4) (cost 10)))
((item 2120) (pants (color white) (size 32) (cost 30)))
((item 2121) (pants (color brown) (size 34) (cost 30)))))
我正在尝试编写一个按项目编号查看列表的函数,return 正确的项目。
(findItem 1001 inventory)
应该 return:
((item 1001) (shoes (color brown) (size 10) (cost 20)))
这是我目前拥有的:
(defun findItem (q i)
(cond
((null q)
nil)
((null (cdr i))
nil)
((eq `parts (car i))
(findItem q (cdr i)))
((eq q (cdr (car (car i))))
(car i))
(T
(findItem q (cdr i)))))
似乎一切正常,除了 ((eq q (cdr (car (car i)))) (car i))
(cdr (car (car i)))
应该 return (1001) 或部件号
但 eq 的计算结果不为真,因此函数总体 return 为零。
将不胜感激
如 What's the difference between eq, eql, equal, and equalp in Common Lisp? 中所述,使用
eq
比较
cons
单元格错误。
您应该使用 equal
或提取
数字,即将 (cdr (car (car i)))
替换为
cadaar
这样
你会得到 1001
而不是 (1001)
.
此外,set
已弃用,请使用
setq
或
defparameter
代替。
此外,您还可以使用内置
find
改为:
(find 1001 (cdr inventory) :key #'cadar)
==> ((ITEM 1001) (SHOES (COLOR BROWN) (SIZE 10) (COST 20)))
(cdr (car (car '((item 1001) (shoes (color brown) (size 10) (cost 20))))))
不起作用,因为 caar
是 item
并且您不能使用符号的 cdr
。
在你做对之前,你应该像这样玩:
(defparameter *item* '((item 1001) (shoes (color brown) (size 10) (cost 20))))
(car *item*) ; ==> (item 1001)
(caar *item*) ; ==> item
(cdar *item*) ; ==> (1001)
现在c<runs of a and d>r
是嵌套car
和cdr
的缩写,例如(car (cdr (cdr x)))
(也称为third
)可以缩写为caddr
当从右到左阅读 as 和 ds 时,您就会明白为什么了。
数字不能保证是 eq
,即使它们表示相同的值。当两个值看起来很相似并且 =
仅适用于在某些实现中可能更快的数字时,您可以使用 equal
来获得真实值。
set
已弃用。使全局变量使用 defparameter
并使用 *earmuffs*
表示它们是全局变量。
我建议您选择合理的名称,因为 q
而 i
并没有任何意义。还使用 CL coding conversion 使您的代码简洁明了,其他 lispers 可读。例如:
(defun find-item (item-number inventory)
"Finds the record in inventory that has a specific item number"
(cond ((endp inventory) nil)
...))
为了扩展 ,让我解决一些文体问题。与任何其他语言一样,您应该尝试设计您的代码以定义一个合理的接口。
我可以告诉你,你可能更喜欢使用结构或对象,但实际上我认为使用列表并不一定不好。令我困扰的是 CADAR
或 CDR
的显式使用:您正在假设您的代码无缘无故地引入了耦合。将抽象与实现分开的第一步是定义访问器函数,如 item-reference
、row-reference
(对于每个条目)等。
如果你碰巧重新组织你的数据,你会很高兴知道你只需要将你定义(item-reference x)
的地方改成(CAADDR x)
(例如)。
顺便说一句,如果您同时提供 :named
和 :type list
参数,Common Lisp structures 可以在列表之上实现。例如,您可以定义一个 item
结构,如下所示:
> (defstruct (item (:type list) :named) reference)
然后,下面实际上构建了一个列表,其中第一个元素表示类型:
> (make-item :reference 300)
=> (ITEM 300)
defstruct
还创建访问器:
> (item-reference *)
300
> (setf (item-reference **) 1010)
1010
你有一个 alist. You should leverage the existing functions that are built in 来处理这个数据结构。
(defun find-item (num list)
(assoc num (cdr list)
:test (lambda (num b)
(equal num (second b)))))
请注意,我还更改了您函数的名称,以便更符合列表样式。
我是 lisp 的新手,如果提出这个问题,我深表歉意。
我有一个列表:
(set ‘inventory ‘(parts
((item 1001) (shoes (color brown) (size 10) (cost 20)))
((item 2011) (skirt (color blue) (size 4) (cost 10)))
((item 2120) (pants (color white) (size 32) (cost 30)))
((item 2121) (pants (color brown) (size 34) (cost 30)))))
我正在尝试编写一个按项目编号查看列表的函数,return 正确的项目。
(findItem 1001 inventory)
应该 return:
((item 1001) (shoes (color brown) (size 10) (cost 20)))
这是我目前拥有的:
(defun findItem (q i)
(cond
((null q)
nil)
((null (cdr i))
nil)
((eq `parts (car i))
(findItem q (cdr i)))
((eq q (cdr (car (car i))))
(car i))
(T
(findItem q (cdr i)))))
似乎一切正常,除了 ((eq q (cdr (car (car i)))) (car i))
(cdr (car (car i)))
应该 return (1001) 或部件号
但 eq 的计算结果不为真,因此函数总体 return 为零。
将不胜感激
如 What's the difference between eq, eql, equal, and equalp in Common Lisp? 中所述,使用
eq
比较
cons
单元格错误。
您应该使用 equal
或提取
数字,即将 (cdr (car (car i)))
替换为
cadaar
这样
你会得到 1001
而不是 (1001)
.
此外,set
已弃用,请使用
setq
或
defparameter
代替。
此外,您还可以使用内置
find
改为:
(find 1001 (cdr inventory) :key #'cadar)
==> ((ITEM 1001) (SHOES (COLOR BROWN) (SIZE 10) (COST 20)))
(cdr (car (car '((item 1001) (shoes (color brown) (size 10) (cost 20))))))
不起作用,因为 caar
是 item
并且您不能使用符号的 cdr
。
在你做对之前,你应该像这样玩:
(defparameter *item* '((item 1001) (shoes (color brown) (size 10) (cost 20))))
(car *item*) ; ==> (item 1001)
(caar *item*) ; ==> item
(cdar *item*) ; ==> (1001)
现在c<runs of a and d>r
是嵌套car
和cdr
的缩写,例如(car (cdr (cdr x)))
(也称为third
)可以缩写为caddr
当从右到左阅读 as 和 ds 时,您就会明白为什么了。
数字不能保证是 eq
,即使它们表示相同的值。当两个值看起来很相似并且 =
仅适用于在某些实现中可能更快的数字时,您可以使用 equal
来获得真实值。
set
已弃用。使全局变量使用 defparameter
并使用 *earmuffs*
表示它们是全局变量。
我建议您选择合理的名称,因为 q
而 i
并没有任何意义。还使用 CL coding conversion 使您的代码简洁明了,其他 lispers 可读。例如:
(defun find-item (item-number inventory)
"Finds the record in inventory that has a specific item number"
(cond ((endp inventory) nil)
...))
为了扩展
我可以告诉你,你可能更喜欢使用结构或对象,但实际上我认为使用列表并不一定不好。令我困扰的是 CADAR
或 CDR
的显式使用:您正在假设您的代码无缘无故地引入了耦合。将抽象与实现分开的第一步是定义访问器函数,如 item-reference
、row-reference
(对于每个条目)等。
如果你碰巧重新组织你的数据,你会很高兴知道你只需要将你定义(item-reference x)
的地方改成(CAADDR x)
(例如)。
顺便说一句,如果您同时提供 :named
和 :type list
参数,Common Lisp structures 可以在列表之上实现。例如,您可以定义一个 item
结构,如下所示:
> (defstruct (item (:type list) :named) reference)
然后,下面实际上构建了一个列表,其中第一个元素表示类型:
> (make-item :reference 300)
=> (ITEM 300)
defstruct
还创建访问器:
> (item-reference *)
300
> (setf (item-reference **) 1010)
1010
你有一个 alist. You should leverage the existing functions that are built in 来处理这个数据结构。
(defun find-item (num list)
(assoc num (cdr list)
:test (lambda (num b)
(equal num (second b)))))
请注意,我还更改了您函数的名称,以便更符合列表样式。