我是LISP编程的新手,这是学期的结束,我们的老师要求我们做这个项目,我一直在努力做到这一点,但我被困住了所以任何帮助都会受到赞赏。该项目是在Lisp中编写一个eval (expr)
函数来覆盖已经存在的函数。这是详细信息:
项目描述:用空格分隔的算术表达式中的项目;
; Input:
; 1. The form of arithmetic expression given in prefix notation like LISP
; Assumptions:
; 1. binary operations for +, -, *, and /
; 2. integer division, no reals
; 3. an arithmetic expression occupies only one line
; 4. nested arithmetic expressions permitted
; 5. all given inputs are syntax correct
; 6. no need for error handling
我编写了一个代码,可以对简单的算术表达式进行评估,并且可以正常工作!但我不能让它在嵌套算术运算上工作。我认为我有一个问题,递归部分我做错了什么,但它究竟是什么idk :(
这是我的代码:
; Assign a character string to a global variable input-prompt
; treat input-prompt as a constant global variable
(setf input-prompt "Please input an arithmetic expression: ")
(setf output-prompt "The value is: ")
(defun prompt-for-input (msg)
(format t msg)
(format t "~%")) ; ~% new line
(defun prompt-for-output (msg)
(format t msg))
(defun output-msg (result)
(format t "~S" result) ; ~S takes the result into the print message
(format t "~%"))
(defun eval (expr)
(print "My EVAL Function is Working *_*")
(if (numberp expr) expr)
(cond
((eq (car expr) '+)
(if (and (numberp (cadr expr))
(numberp (caddr expr))) ;to check if we have simple expression
(+ (cadr expr) (caddr expr)) ;in case both are numbers we add normally
(if (not (numberp (cadr expr)))
;in case the second argument is not number
;we need to call eval again to check the expression
((eval (cadr exp)))
(if (not (numberp (caddr expr)))
;in case the third argument is not a number
;we need to call eval again to check the expression
((eval (caddr exp)))
(0)))))
((eq (car expr) '-)
(if (and (numberp (cadr expr))
(numberp (caddr expr))) ;to check if we have simple expression
(- (cadr expr) (caddr expr)) ;in case both are numbers we add normally
(if (not (numberp (cadr expr)))
;in case the second argument is not number
;we need to call eval again to check the expression
((eval (cadr exp)))
(if (not (numberp (caddr expr)))
;in case the third argument is not a number
;we need to call eval again to check the expression
((eval (caddr exp)))
(0)))))
((eq (car expr) '*)
(if (and (numberp (cadr expr))
(numberp (caddr expr))) ;to check if we have simple expression
(* (cadr expr) (caddr expr)) ;in case both are numbers we add normally
(if (not (numberp (cadr expr)))
;in case the second argument is not number
;we need to call eval again to check the expression
((eval (cadr exp)))
(if (not (numberp (caddr expr)))
;in case the third argument is not a number
;we need to call eval again to check the expression
((eval (caddr exp)))
(0)))))
((eq (car expr) '/)
(if (and (numberp (cadr expr))
(numberp (caddr expr))) ;to check if we have simple expression
(/ (cadr expr) (caddr expr)) ;in case both are numbers we add normally
(if (not (numberp (cadr expr)))
;in case the second argument is not number
;we need to call eval again to check the expression
((eval (cadr exp)))
(if (not (numberp (caddr expr)))
;in case the third argument is not a number
;we need to call eval again to check the expression
((eval (caddr exp)))
(0)))))))
; it should have eval(expr) function which returns the value of the
; arithmetic expression
; for instance,
; (+ 2 3) outputs 5
; (+ (* 3 2) (/ 4 2))) outputs 8
; (* (- 2 3) 5) outputs -5
; driver accepts the input arithmetic expression
; evaluate the arithmetic expression
; output the reulst of the evaluation of the arithmetic expression
; execution is in the loop; to exit the loop; type cntrl-c
(defun driver ()
(prompt-for-input input-prompt)
;to print "Please input an arithmetic expression
(let ((expression (read)))
(output-msg expression)
(let ((result (eval expression)))
(prompt-for-output output-prompt)
(output-msg result)))
(driver))
答案 0 :(得分:2)
一些提示:
(0)
之类的表达没有意义。 0
不是函数。类似的((foo))
也没有意义。
你应该正确格式化和缩进Lisp代码。编辑帮助。
避免使用CAR
,CDR
,CADR
,...等功能 - 使用FIRST
,REST
,SECOND
, ...
不要调用函数EVAL
。这是Common Lisp中的内置函数。
答案 1 :(得分:2)
首先,这个技巧的基本召唤是......鼓声...... -
(apply (symbol-function (car expr)) (cdr expr))
这假设 - 暂时 - 表达式中的所有参数都已经是数字。
这一行代替了代码中的所有四个案例,这些案例都是彼此完全相同的副本,直到要执行的操作。
现在,为了确保我们有数字,我们只需要在每个数字上调用相同的eval
。如果它们是数字,它们将保持原样,如果不是 - 它们将被评估。
我们只需拨打我们的新功能calc
,即可#34;计算",而不是:
(defun calc (expr) ; our "eval"
(cond
((numberp expr) expr)
(T (call (car expr)
(mapcar #'calc (cdr expr))))))
(defun call (op args) ; our "apply"
(apply (symbol-function op)
args))
这就是全部。如果你考虑这种作弊行为,你可以手动调用该操作,但是你仍然不需要复制相同的代码块四次。 :)
如果您确实亲自编写call
来手动调用操作,请注意(*)
的默认值为1,而不是0;并且Common Lisp中的(-)
和(/)
没有默认值(在CLisp中测试过)。此外,(/ 2)
应返回1/2
。