为什么Common Lisp内层loop的collect操作没有返回预期结果?
Common Lisp loop写法错误原因分析
1. 基础语法错误:let表达式括号不配对
你第一版代码存在明显的括号匹配错误,let声明的变量绑定列表没有正确闭合:
;; 错误写法 (let ((res (list)) (loop ...))
Common Lisp中let的标准语法结构是(let ((变量1 初始值) (变量2 初始值) ...) 执行体),你上述写法相当于把整个loop表达式错误放到了变量绑定列表中,既没有完成res变量的绑定声明,也没有正确定义let的执行体,属于基础语法错误。
2. loop宏collect into的作用域限制
就算你修正了括号问题,第一版代码依然无法正常运行,核心原因是loop宏中into关键字声明的收集变量是当前loop的局部变量,作用域仅在该loop内部,不会和外层let声明的同名变量绑定:
你在内层y循环中写的collect (aref mapa x y) into res,这里的res是loop宏自动创建的局部临时变量,内层循环结束后就会被销毁,完全不会修改外层let声明的res变量。
同时第一版代码没有显式的返回值声明,Common Lisp函数默认返回最后一个表达式的执行结果,而没有显式收集/返回子句的loop表达式默认返回nil,这就是你第一版代码只得到nil的核心原因。
3. 符合loop设计逻辑的优化写法
你第二版代码通过push显式修改外层变量、最后主动返回res的写法是可行的,如果你想更贴合loop的原生设计,不需要额外声明外部变量,可以直接用append拼接内层循环的收集结果:
(defun coll-intersects (bounds mv) (loop for x from (first bounds) to (+ (first bounds) (third bounds)) append (loop for y from (second bounds) to (+ (second bounds) (fourth bounds)) for val = (aref mapa x y) when (not (member (cl-byte val) mv)) collect val)))
内层loop收集每一行符合要求的元素返回列表,外层loop把所有行的列表拼接为最终结果,整个loop的返回值就是函数的返回值,写法更简洁。
内容的提问来源于stack exchange,提问作者Akasha
相关产品推荐
相关产品推荐

