Common Lisp函数仅返回函数名问题排查:Project Euler第1题求解遇阻
问题分析:Project Euler第1题Lisp函数返回函数名的问题
我正在求解projecteuler.net的第1题,但执行以下函数时仅返回函数名称,请问我哪里出错了?
你的代码存在几处关键的语法和逻辑错误,导致函数定义不合法,解释器无法正确创建可执行的函数,所以调用时会返回函数对象的名称而非计算结果。先看你的原始代码:
(defun nSum (n sum) (if ( n = 0) ( sum) ) (cond ( (mod n 5) = 0) ( nSum ( - n 1) (+ sum n)) ( (mod n 3) = 0) (nSum(- n 1) (+ sum n)) (nSum (- n 1) (+ sum n)) ) ) (setq sum (nSum 100 0)) (write sum)
具体错误点:
- 前缀表达式语法错误:Lisp是前缀表达式语言,所有操作符必须放在表达式最前面。你写的
(n = 0)应该是(= n 0),(mod n 5) = 0应该是(= (mod n 5) 0)——把判断符=放在最前面,包裹住要比较的两个值。 if语句结构错误:Lisp的if格式是(if 条件 真分支 假分支),你现在的if没有假分支,而且(sum)是试图调用名为sum的函数,但sum是你的参数变量,直接写sum即可返回它的值。更关键的是,当前代码里if执行完后会继续运行后面的cond,这完全破坏了递归的终止逻辑。cond分支格式错误:cond的每个分支必须是(条件 执行代码)这样的列表。你把条件和执行代码拆成了独立的元素,比如((mod n 5) = 0)和(nSum ...)是两个分开的元素,这会被解释器当成无效的分支结构。- 递归终止逻辑失效:即使n=0,你的代码也会继续执行后面的
cond,导致递归无法停止,最终要么报错,要么因为前面的语法错误让函数定义失败。
修正后的代码:
(defun nSum (n sum) (if (= n 0) sum ; n为0时返回累计的sum,终止递归 (cond ; 如果n能被3或5整除,累加n后递归 ((or (= (mod n 5) 0) (= (mod n 3) 0)) (nSum (- n 1) (+ sum n))) ; 其他情况直接递归,不累加 (t (nSum (- n 1) sum))))) ; 注意:Project Euler第1题是求小于1000的数,这里按你写的100来,实际应该用999 (setq result (nSum 99 0)) (write result)
为什么之前返回函数名称?
当函数定义存在语法错误时,Lisp解释器无法正确编译生成可执行的函数对象。此时你调用nSum,解释器会把它当成对函数符号本身的引用,所以返回函数的名称(比如NSUM)。修正语法后,函数就能正常执行递归计算了。
内容的提问来源于stack exchange,提问作者Peter Timperman
相关产品推荐
相关产品推荐

