Lisp Arith eval(通用口齿不清:温和的介绍)
我正在学习,想解决所有的练习 有时我有不同的解决办法。这让我很困惑,我不容易理解这本书的标准答案 例如,使用Lisp Arith eval(通用口齿不清:温和的介绍),lisp,common-lisp,Lisp,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))))))))) 本书的解决方案: (defun
arith eval
:
我的解决办法是:
(defun arith-eval (x)
(cond
((atom x) x)
(t (eval (cons (cadr x)
(cons (car x)
(list (arith-eval (caddr x)))))))))
本书的解决方案:
(defun arith-eval (exp)
(cond ((numberp exp) exp)
(t (funcall (second exp)
(arith-eval (first exp))
(arith-eval (third exp))))))
在这种情况下我能做什么?让我们从“eval
和funcall
是非常不同的野兽”开始
eval
函数接受一个S表达式,并在“空词汇环境”(本质上,只有动态变量可见)中对其求值。funcall
函数采用函数指示符(函数对象或具有函数绑定的符号)和0个或多个参数。按照normal with函数,参数是在当前词汇环境中计算的
在一般情况下,我建议不要使用eval
,除非您绝对需要,funcall
或apply
几乎总是解决此类问题的正确工具。让我们从“eval
和funcall
是非常不同的两种工具”开始
eval
函数接受一个S表达式,并在“空词汇环境”(本质上,只有动态变量可见)中对其求值。funcall
函数采用函数指示符(函数对象或具有函数绑定的符号)和0个或多个参数。按照normal with函数,参数是在当前词汇环境中计算的
在一般情况下,我建议不要使用eval
,除非您绝对需要,funcall
或apply
几乎总是解决此类问题的正确工具。您的解决方案是a)不正确,b)使用错误的方法
正确性
您的函数支持像(1+(2+3))
这样的表达式,但不支持((1+2)+3)
当您编写这样一个解决方案时,您需要考虑什么是可能的算术表达式,以及您的代码是否能够计算出一个解决方案。此外,考虑有用的测试用例并运行它们也是一个好主意:
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))))
方法
您的代码创建一个Lisp表单,然后调用eval
,并以递归的方式执行
解决Lisp练习的第一条规则:不要使用EVAL
有一种更好的方法:
- 由于表达式中的运算符符号已经是有效的Lisp函数,因此可以调用该函数并提供正确的参数。我们可以利用内置的求值功能,通过递归调用
来计算参数。这就是书中的解决方案arith eval
eval
有意义:
- 将整个表达式从中缀转换为前缀一次,然后调用
(此处eval
可能有意义)eval
(eval(中缀到前缀表达式))
现在必须将函数中缀写入前缀您的解决方案是a)不正确,b)使用错误的方法
正确性
您的函数支持像(1+(2+3))
这样的表达式,但不支持((1+2)+3)
当您编写这样一个解决方案时,您需要考虑什么是可能的算术表达式,以及您的代码是否能够计算出一个解决方案。此外,考虑有用的测试用例并运行它们也是一个好主意:
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))))
方法
您的代码创建一个Lisp表单,然后调用eval
,并以递归的方式执行
解决Lisp练习的第一条规则:不要使用EVAL
有一种更好的方法:
- 由于表达式中的运算符符号已经是有效的Lisp函数,因此可以调用该函数并提供正确的参数。我们可以利用内置的求值功能,通过递归调用
arith eval
来计算参数。这就是书中的解决方案
仍然可能有一个解决方案,eval
有意义:
- 将整个表达式从中缀转换为前缀一次,然后调用
eval
(此处eval
可能有意义)
类似于(eval(中缀到前缀表达式))
现在需要编写函数中缀到前缀
,谢谢你的回答,我很高兴。但我真的很想知道人们是如何根据这本书的教程得到标准答案的。这对我来说毫无逻辑。@programer5566从未读过那本书,我想我是从温斯顿和霍恩(亚马逊链接:)的“Lisp”开始的,作为一个教程。这可能值得一读,对于一个标准文档来说,它的可读性令人惊讶。谢谢梵蒂娜,你是如此的友好和友好。我会找到这本书的,我很高兴见到你。谢谢你的回答,我很高兴。但我真的很想知道人们是如何根据这本书的教程得到标准答案的。这对我来说毫无逻辑。@programer5566从未读过那本书,我想我是从温斯顿和霍恩(亚马逊链接:)的“Lisp”开始的,作为一个教程。这可能值得一读,对于一个标准文档来说,它的可读性令人惊讶。谢谢梵蒂娜,你是如此的友好和友好。我会找到这本书的,很高兴见到你。谢谢乔斯威格先生!我不知道如何对你的回答表示感谢。我只是试着理解什么是测试用例,现在就努力学习谢谢Joswig先生!我不知道如何对你的回答表示感谢。我只是试着理解什么是测试用例,现在就努力学习