2010.01.14 11:44

taoi part0 -session 4 MC Eval Proper

이제 시간도 조금 있고 놀만한 시간이 되었다.

놀이를 위한 시간은 의외로 부족하다.  항상 정신이 없으니 ...


망각 대왕인 나는 지난번 읽었던 것들을 모두 까먹었다.  이 와중에 메모리가 512 Mb 밖에 안되는 컴퓨터는 버벅대고 있다. 창 몇 개만 띠우면 ... 이정도면 결코 부족한 자원이 아닌데 다른 PC의 사양들에 익숙해져서 그런 것 같다. 예전 같으면 슈퍼 컴퓨터보다 좋은 상황이다. 혹시 모르니 나중에 윈도우에서 리눅스로 다시 가볼까 하는 생각이 든다.


아무튼 너무 시간을 끌면 재미가 적어지니 이번에는 돌아가는 인터프리터를 만들어 보려고 한다. 비공개된 블로그 중에는 explicit controller 의 Evaluator 를 작업 중이다.  글만 보고 이해가 불가능한 부분이기도 하다.


------------------------------------------------------------

아뜨오브 인터프리터의 앞부분에는 두개의 버전이 나온다.


첫 번째는 데이터는 env 에 프로시저 데이터는 procedure 에 저장하는 형태의 인터프리터이고 

두 번째는  procedure를  없애고 env 만 사용하는 형태의 인터프리터다. 

둘다 충분히 갖고 놀며 생각해 볼 여지가 많은 인터프리터다.   

 

오늘은 우선 procedure 를 사용하여 함수를 따로 정의하는 인터프리터다. 


우선 엉성하게 eval을 정의해 보자

지난번의 정의환경에 다음과 같이 더해보자.

TAOI의 9페이지에 나온 Eval 이다.

r5rs에는 atom 이라는 함수가 없다.

LISP의 식은 atom 이거나 lsit 둘 중의 하나다. 여기에 해당하는 키워드는 pair? 또는 list? 이다.


(define (mceval exp env procedures)

  (cond ((not (list? exp)) ;;atom exp

        ( cond

           ((eq? exp '#f) #f)

           ((eq? exp '#t) #t)

           ((number? exp ) exp)

           (else  (value exp env))

         ))

     

        ((eq? (car exp) 'quote)  (cadr exp))

        ((eq? (car exp) 'cond) ( evcond (cdr exp)  env procedures))

       

        (else

         (mcapply (value (car exp) env procedures)

                (evlis (cdr exp)  env procedures)))

       ))


(define (evcond clauses env procedures )


    (cond ((null? clauses) 'error)

          ((mceval (caar clauses) env procedures)

           (mceval (cadar clauses) env procedures))

      (else (evcond (cdr clauses) env  procedures))))



다 돌아가는 것은 아니지만 우선적으로 몇가지는 테스트할 수 있다.

lookup과 bind 를 이미 구성했으므로 driver loop의 신세를 지지 않고도 돌려볼 수 있다.



우선 #t #f 그리고 숫자에 대한 테스트를 해보자 . 환경은 ENV 와 procedure 둘 다 ‘()로 정하자.


무사히 통과한다.


> (mceval #t '() '())

#t

> (mceval #f '() '())

#f

> (mceval 3 '() '())

3


그 다음은 변수를 찾는 연습이니 bind를 써서 환경을 만든다.

> (bind '(c d) '(3 4) '())

(((c d) 3 4))


mceval exp env procedures 순서이니 다음과 같이 돌려보자


> (mceval 'c  '(((c d) 3 4)) '())

3

> (mceval 'd  '(((c d) 3 4)) '())

4

c 와 d는 변수이다.  value 는 (value exp env) 와 같은 문법으로 값을 돌려준다. 여기서 찾은 것은 변수 c 와 d 의 값이다.


여기까지의 예제는 값들이 atom 인 경우다. 무사히 통과한 것 같다.


이제부터는 list 인 경우다.


우선 첫 번째로 quote 의 test를 해보자.

다들 알고 있는 바와 같이 ‘3 ’5 는 내부적으로

(quote 3) (quote 5) 같이 표기된다.


> (mceval (quote 3) '() '())

3

> (mceval '(quote 3) '() '())

3

> (mceval '(quote X) '() '())

x

> (mceval (quote X) '() '())

error


만약 x 가 환경에 있다면  당연히 찾아서 값을 내어줄 것이다.


> (mceval (quote X) '(((x d) 3 4)) '())

3


오 ! 이번에도 무사히 통과했다. 마지막은 변수 x 를 직접 부른 것과 마찬가지이니 변수를 찾지 못해 에러가 나온 것이다.


그 다음은 cond 문이다.


아주 간단히 테스트 해볼 수 있다.


첫번째 만나는 cond의 평가식이 참이면 그조건과 같이 주어진 식을 계산한다. 

아무것도 충족되는 조건이 없으면 에러를 내거나 '()를 되돌린다. 


> (mceval '(cond (#t 1)(#f 3)) '() '())

1

> (mceval '(cond (#f 1)(#t 3)) '() '())

3

>(mceval '(cond (#f 1)(#f 3)) '() '())

error


cond 문의 정의에서  생각해 보면 동작은 올바르다.

이제 apply 만 잘 빠져 나오면 간단하지만 근본적인 동작을 하는 인터프리터의 원형을 얻을 수 있다. 당분간 잘 놀 수 있는 인터프리터이다.

 


이제 남은 문제는 apply 이다. apply의 형태는 다음과 같다.

별로 어려워 보이지 않는다. 그러나 그 이전에 primeop 라는 것을 생각해 봐야 한다.

이것은 내일이나 모레의 주제다. 이 주제를 쉽게 설명하려면  궁리해 보아야 한다. 

아직은 어려운 부분이 없었다고 생각한다. 


(define (mcapply fun args procedures )

  (cond ((primop fun)

         (apply-primitive-procedure procedure args))

       

        (else mceval (cadr fun ) (bind car fun args '() procedures))))




Trackback 0 Comment 0