2013-04-24 2 views
3

저는 LISP 프로그래밍을 처음 접했고 학기가 끝났으며 선생님이이 프로젝트를 수행하라고 요청했습니다. 그래서 어떤 도움을 주시면 감사하겠습니다. 프로젝트는 이미 존재하는 함수를 덮어 쓰기 위해 eval (expr) 함수를 Lisp에 작성합니다. 여기에 세부 사항 :LISP의 함수 (defun 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 

간단한 산술 표현식의 평가를 할 수있는 코드를 작성했습니다. 하지만 중첩 된 산술 연산에 대해서는 작동하지 않아야합니다. 나는 내가 뭔가 잘못하고있는 중이 야 재귀 부분에 문제가 있다고 생각하지만, 정확히 나도 몰라 무엇을 여기

:(내 코드입니다 :

; 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

SO에 소스 코드를 게시 할 때 탭을 사용하지 마십시오. :) 항상 코드를 올바르게 들여 쓰도록 노력하십시오. 가능한 경우 코드 창 너비에 선을 맞추어 수평 스크롤 막대가 없도록하십시오 (요구 사항은 아니지만 그런 식으로 코드를 읽는 것이 훨씬 쉽습니다) . –

+0

태그가 너무 많습니다. 엘프인가? XLisp? 또는 Common Lisp? – Kaz

답변

2

첫째, 트릭이 수행하는 기본 호 ... 드럼 롤 ... -

(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을 직접 작성하여 작업을 호출하는 경우 (*)의 기본값은 0이 아니라 1입니다. Common Lisp에는 (-)(/)에 대한 기본값이 없다 (CLisp에서 테스트 됨). 또한 (/ 2)1/2을 반환해야합니다.

+0

@ Will Ness 정말 고마워요! 적은 코드로 효과적입니다. 너는 바위 야. 당신의 도움에 감사드립니다. –

+0

@AriannaNewman 당신은 매우 환영합니다. Lisp의 경이로움에 오신 것을 환영합니다! (그리고 Scheme, 그리고 Haskell, ... 만약 당신이 당신의 스케줄에 맞출 수 있다면 - Prolog). :) –

+0

@AriannaNewman 또한'driver' 함수를 다시 작성하십시오. Common Lisp에는 꼬리 재귀 보장이 없습니다 IIRC, 당신이 쓴 내용은 Scheme 코드와 비슷합니다. [do' (http://www.lispworks.com/documentation/HyperSpec/Body/m_do_do.htm)를 사용하면 루프에서 빠져 나갈 수있는 방법을 고안 할 수 있습니다. –

2

몇 가지 힌트 :

  • (0)과 같은 표현식은 의미가 없습니다. 0은 기능이 아니며 마찬가지로 ((foo))도 의미가 없습니다.

  • uld는 Lisp 코드를 적절히 형식화하고 들여 쓰기합니다. 편집자가 도움이됩니다. 같은

  • 피 기능 CAR, CDR, CADR, ... - 사용 FIRST, REST, SECOND ...

  • 함수 EVAL를 호출하지 않습니다. 이것은 Common Lisp의 내장 함수입니다. 모든