我试图使用标准的循环工具来收集结果,但它只返回nil。为什么会这样呢?我觉得这应该行得通:
(defun coll-intersects (bounds mv)
(let ((res (list))
(loop for x from (first bounds) to (+ (first bounds) (third bounds)) do
(loop for y from (second bounds) to (+ (second bounds) (fourth bounds))
if (not (member (cl-byte (aref mapa x y)) mv))
collect (aref mapa x y) into res
))))但不,我必须这么做:
(defun coll-intersects (bounds mv)
(let ((res (list)))
(loop for x from (first bounds) to (+ (first bounds) (third bounds)) do
(loop for y from (second bounds) to (+ (second bounds) (fourth bounds))
do
(if (not (member (cl-byte (aref mapa x y)) mv))
(push (aref mapa x y) res))
))
res))为什么?我真的很困惑为什么第一个不能工作
发布于 2021-06-03 19:48:33
正如Ehvince的回答所说,问题是
(loop ...
collect ... into x
...)绑定x。此构造的目的实际上是让您可以收集多个列表:
(defun partition (l)
(loop for e in l
if (evenp e)
collect e into evens
else
collect e into odds
finally (return (values evens odds))))例如。
如果你想从嵌套循环中收集一个列表,并且你关心的是顺序,你可以这样做:
(defun sublist-evens (l)
(loop for s in l
nconcing
(loop for e in s
when (evenp e)
collect e)))在这里,外部循环本质上是将来自内部循环的结果nconc在一起。这当然可以嵌套:
(loop ...
nconcing
(loop ...
nconcing
(loop ...
collect ...)))都会起作用的。也有可能loop足够聪明,可以保持一个指向它使用nconc / nconcing构建的列表的尾部指针,尽管您必须检查这一点。
但是,如果您想从一些深度嵌套的循环(或任何其他搜索过程)按顺序构建一些列表,我发现使用collecting macro来做这件事几乎总是更令人愉快的(免责声明:这篇文章是我写的)。使用这样的宏,上面的sublist-evens函数如下所示:
(defun sublist-evens (l)
(collecting
(dolist (s l)
(dolist (e s)
(when (evenp e) (collect e))))))和
> (sublist-evens '((1 2 3) (4 5 6)))
(2 4 6)你可以做得更好:
(defun tree-partition (tree)
(with-collectors (evens odds)
(labels ((search (it)
(typecase it
(list
(dolist (e it)
(search e)))
(integer
(if (evenp it)
(evens it)
(odds it)))
(t
(warn "unexpected ~A" (type-of it))))))
(search tree))))而现在
> (tree-partition '(((1 2 3) (4)) 5))
(2 4)
(1 3 5)(对于hack值,您可以使用another macro来更简洁地表达上面的内容:
(defun tree-partition (tree)
(with-collectors (evens odds)
(iterate search ((it tree))
(typecase it
(list
(dolist (e it)
(search e)))
(integer
(if (evenp it)
(evens it)
(odds it)))
(t
(warn "unexpected ~A" (type-of it)))))))免责声明:那个宏也是我写的。)
发布于 2021-06-03 18:04:40
下面是第一个代码片段,其中更正了let括号,并将其简化为可重现:
(defun coll-intersects (bounds mv)
(let ((res (list))) ;; <-- third closing paren
(loop for x from (first bounds) to (+ (first bounds) (third bounds)) do
(loop for y from (second bounds) to (+ (second bounds) (fourth bounds))
if (evenp y)
collect y into res
))))现在,当我将其输入REPL时,SBCL会警告我有一个未使用的res。
; caught STYLE-WARNING:
; The variable RES is defined but never used.这是一个很大的提示。
我想看到的问题是:
对于外部循环,你使用的是nil.
collect … into,而不是res,而且你不会返回res,所以函数总是返回nil.
collect … into,大概是使用了内部变量,而不是你的res :S此外,循环没有说明如何处理它。我添加了finally (return res),我得到了结果。您还可以像第二个示例中那样使用push。但是,使用外部let.
声明中间变量时,通常不需要使用collect y.
into下面是一个返回(哑巴)结果的更简单的函数:
(defun coll-intersects (bounds)
(loop for x from (first bounds) to (+ (first bounds) (third bounds)) collect
(loop for y from (second bounds) to (+ (second bounds) (fourth bounds))
if (evenp y)
collect y)))
(coll-intersects '(1 2 3 4))
((2 4 6) (2 4 6) (2 4 6) (2 4 6))如果您使用nconcing而不是第一个collect,您将得到一个平面列表(如@tfb所指出的)。
或者:
(defun coll-intersects (bounds)
(let ((res (list)))
(loop for x from (first bounds) to (+ (first bounds) (third bounds)) do
(loop for y from (second bounds) to (+ (second bounds) (fourth bounds))
if (evenp y)
do (push y res)
))
res))
(coll-intersects '(1 2 3 4))
(6 4 2 6 4 2 6 4 2 6 4 2)发布于 2021-06-03 15:49:06
在第一个示例中,函数的返回值是外部循环的返回值。它不收集任何值(内部循环收集),因此很可能只返回一个nil。
在第二个示例中,您的函数显式返回res的值。
https://stackoverflow.com/questions/67817363
复制相似问题