dav*_*ugh 1 macros common-lisp anonymous-function
Common Lisp宏pushnew返回作为参数给出的(可能已更新)位置列表。看来,如果您想知道给定的项目是否实际被推送,则需要比较放置前和放置后列表以查看其是否已更改。但这对于我的使用来说效率太低,因为它将涉及重复比较两个复杂结构对象的列表以得出等效结果。
另一种可行的替代方法是使用:test参数来pushnew记录是否已找到该项目,因为已扫描列表元素。如果找到该项目,则可以将T作为第二个整数值返回,否则返回NIL。下面的宏尝试执行此操作:
(defmacro pushnew+p (item place &key test (key #'identity) &aux old?)
"Same as pushnew, but also returns whether item was pushed."
`(values (pushnew ,item ,place
:test (lambda (item element)
(if ,test
(setf old? (funcall ,test item element))
(setf old? (eql item element))))
:key ,key)
(not old?)))
Run Code Online (Sandbox Code Playgroud)
似乎工作正常,因为
(defparameter x '(1 2 3))
(pushnew+p 0 x) -> (0 1 2 3), T
(pushnew+p 2 x) -> (0 1 2 3), NIL
(defparameter y '((1) (2) (3)))
(pushnew+p '(0) y :test #'equal) -> ((0) (1) (2) (3)), T
(pushnew+p '(2) y :test #'equal) -> ((0) (1) (2) (3)), NIL
Run Code Online (Sandbox Code Playgroud)
但是,我不确定:test参数的工作方式,并且Hyperspec条目pushnew未明确说明。是否保证列表元素的测试会在测试返回T时立即停止(如需要)?(或者remove,测试应该继续进行到序列的末尾。)如果测试继续进行到末尾,那么return-from尽早终止的最佳方法是吗?
另一个问题是匿名lambda主体反复检查,test每个元素的给定参数。可以将其移出lambda吗?感谢您的任何建议。
我认为,更好的办法是检查是否有新的元素,其实,前置按规定pushnew:
(unless (eq item (car place))
(pushnew item place ...)
(when (eq item (car place))
;; not found, prepended
))
Run Code Online (Sandbox Code Playgroud)
请注意,即使您传递:test给pushnew,您仍然可以eq在unless和中使用when。
PS。请注意@coredump评论中提到的特殊情况。
| 归档时间: |
|
| 查看次数: |
65 次 |
| 最近记录: |