문제

I am new to LISP programming and it is the end of semester and our teacher asked us to do this project and I have been trying to make it but I am stuck so any help would be appreciated. the Project is to write an eval (expr) function in Lisp to overwrite the already existing function. here is the details:

Project Description: Items in an arithmetic expression separated by spaces;

; 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  

I wrote a code that can do eval of the simple arithmetic expressions and it works!! but I COULD NOT get it to work on nested arithmetic operations. I think I have an issue with the recursion part i am doing something wrong but what is it exactly idk :(

here is my code :

; 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))
도움이 되었습니까?

해결책

First of all, the basic call that does the trick is ... drum roll ... -

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

this assuming - for a moment - that all the arguments in the expression are already numbers.

This one line replaces all four cases in your code which are all exact copies of one another, up to the operation to be performed.

Now, to make sure we have numbers, we just need to call same eval on each of them. If they were numbers, they will stay as is, and if not - they'll get evaluated.

Let's just call our new function calc, for "calculate", instead:

(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))

That's all. If you consider this cheating, you can call the operation by hand, but still you don't need to copy the same block of code four times for that. :)

If you indeed write the call yourself to call the operation by hand, do note that the default value for (*) is 1, not 0; and that there's no default value for (-) and (/) in Common Lisp (as tested in CLisp). Also, (/ 2) should return 1/2.

다른 팁

a few hints:

  • Expressions like (0) are not meaningful. 0 is not a function. Similar ((foo)) also makes no sense.

  • you should properly format and indent Lisp code. The editor helps.

  • Avoid functions like CAR, CDR, CADR, ... - use FIRST, REST, SECOND, ...

  • don't call the function EVAL. That's a built-in function in Common Lisp.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top