3

我是 LISP 编程的新手,现在是学期末,我们的老师要求我们做这个项目,我一直在努力完成它,但我被卡住了,所以任何帮助都将不胜感激。项目是eval (expr)在 Lisp 中编写一个函数来覆盖已经存在的函数。这是详细信息:

项目描述:以空格分隔的算术表达式中的项目;

; 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))
4

2 回答 2

3

首先,起到作用的基本调用是......鼓声...... -

(apply (symbol-function (car expr)) (cdr expr))

这假设 - 暂时 - 表达式中的所有参数都已经是数字。

这一行替换了代码中的所有四种情况,它们都是彼此的精确副本,直到要执行的操作。

现在,为了确保我们有号码,我们只需要eval在每个号码上调用相同的号码。如果它们是数字,它们将保持原样,如果不是 - 它们将被评估。

让我们只调用我们的新函数calc“计算”,而不是:

(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

于 2013-04-24T19:30:40.023 回答
2

一些提示:

  • 像这样的表达(0)没有意义。0不是函数。类似((foo))也没有任何意义。

  • 你应该正确地格式化和缩进 Lisp 代码。编辑帮忙。

  • 避免使用 , , , ... 之类的功能-使用, CAR, CDR, ...CADRFIRSTRESTSECOND

  • 不要调用函数EVAL。这是 Common Lisp 中的内置函数。

于 2013-04-24T17:25:57.897 回答