我正在学习Common Lisp:一个温和的介绍,想要解决所有的练习.
有时我有不同的解决方案.它使我困惑,我不能轻易理解本书的标准答案.
例如,用arith-eval:
我的解决方案是:
(defun arith-eval (x)
(cond
((atom x) x)
(t (eval (cons (cadr x)
(cons (car x)
(list (arith-eval (caddr x)))))))))
Run Code Online (Sandbox Code Playgroud)
这本书的解决方案:
(defun arith-eval (exp)
(cond ((numberp exp) exp)
(t (funcall (second exp)
(arith-eval (first exp))
(arith-eval (third exp))))))
Run Code Online (Sandbox Code Playgroud)
在这种情况下我该怎么办?
您的解决方案是a)不正确,b)使用错误的方法.
正确性
您的函数支持表达式(1 + (2 + 3)),但不支持((1 + 2) + 3).
CL-USER 6 > (arith-eval '((3 * 5) + 1))
Error: Illegal car 3 in compound form (3 * 5).
Run Code Online (Sandbox Code Playgroud)
在编写这样的解决方案时,您需要考虑可能的算术表达式以及您的代码是否可以计算解决方案.另外,考虑有用的测试用例并运行它们是个好主意:
CL-USER 14 > (defparameter *test-cases*
'( ( ((1 + 2) + 3) . 6)
( (1 + 2 + 3) . 6)
( (1 + (2 + 3)) . 6)))
*TEST-CASES*
CL-USER 15 > (loop for (test . result) in *test-cases*
collect (list (ignore-errors (eql (arith-eval test)
result))
test))
((NIL ((1 + 2) + 3)) ; failed
(NIL (1 + 2 + 3)) ; failed, but probably not required
(T (1 + (2 + 3))))
Run Code Online (Sandbox Code Playgroud)
途径
您的代码创建一个Lisp表单,然后调用eval,并以递归方式执行.
解决Lisp练习的第一条规则:不要使用EVAL
有一个更好的方法:
arith-eval递归调用来计算参数.这是书中的解决方案.仍然可能有一个eval有意义的解决方案:
eval(这里eval可以有意义).有点像(eval (infix-to-prefix expression)).
现在必须编写该函数infix-to-prefix.