Lisp出现SYSTEM::READ-EVAL-PRINT错误:变量未赋值问题求助
问题排查与解决方案
看起来你在Common Lisp里遇到了变量作用域和参数传递的典型问题,我来帮你拆解清楚:
错误原因分析
1. 调用时的变量未定义错误
当你执行(test j 10)时,Common Lisp的解释器会先对每个实参求值。第一个实参是j,但你之前从来没有给这个变量赋过值,所以解释器自然会抛出SYSTEM::READ-EVAL-PRINT: variable J has no value的错误。之前出现的I has no value也是同理——比如你曾经调用过(test 5 i),这时候i是未定义的变量,就会触发相同的报错。
2. 函数内部的逻辑误区
你的函数定义:
(DEFUN test (j i) (LET ((j i)) (print j) ) )
这里有个多余的LET绑定:你已经把j作为函数的参数(局部变量),但又在LET里重新创建了一个同名的局部变量j,它会覆盖参数里的j,然后把参数i的值赋给这个新的j。其实这个LET完全没必要,因为你直接操作参数j就可以了。
另外,从你的调用意图(test j 10)来看,你可能想把10这个值赋给外部的变量j,但Common Lisp的函数参数是按值传递的——函数内部的j是局部变量,和外部的j没有关联,修改它不会影响外部的变量。
解决方案
根据你的需求,分两种情况给出正确的写法:
情况1:仅在函数内部使用赋值后的j
如果你只是想在函数内部让局部变量j等于参数i的值,然后打印它,可以简化函数:
(DEFUN test (j i) (setf j i) ; 把i的值赋给局部变量j (print j))
调用的时候要确保实参是已定义的变量或者字面量:
;; 方式1:先给j赋值,再调用 (setf j 5) (test j 10) ; 函数内部把局部j改成10,打印10 ;; 方式2:直接传字面量 (test 5 10) ; 同样打印10
情况2:修改外部的变量j
如果你想让外部的变量j被赋值为10,最规范的方式是通过函数返回值来实现(避免直接操作全局变量):
(DEFUN get-value (value) (print value) value) ; 返回传入的value (setf j (get-value 10)) ; 把函数返回的10赋给外部变量j (print j) ; 现在j的值是10
如果你一定要直接修改外部变量(不推荐,会破坏代码封装性),可以通过操作符号值来实现:
(DEFUN set-variable (var value) (setf (symbol-value var) value) (print (symbol-value var))) (set-variable 'j 10) ; 注意这里传的是符号'j,不是变量j (print j) ; 此时j的值为10
关键知识点总结
- Common Lisp调用函数时会先求值所有实参,所以实参必须是已定义的变量或字面量。
- 函数的参数是局部变量,修改它们不会影响外部的同名变量。
- 要修改外部变量,优先通过返回值赋值的方式,这是更符合Lisp编程风格的做法。
内容的提问来源于stack exchange,提问作者Samson Bankole
相关产品推荐
相关产品推荐

