SSブログ

EOPL 第3章の Exercise 3.25 [Lisp]

前回のレキシカル変数に名前は不要というアプローチを推し進めて環境から完全に名前を消してしまう。これにより env 系の関数は非常に単純になった。プログラムの字面の解析を事前に手厚くしておく分だけ実際の実行が単純になるということかな。

前回の練習問題では lexical-address 関数が変数を lexvar に変換できなかった場合(つまり自由変数の場合)も考慮しておいたのだけど env 系関数から変数名が消えたことによりこれが意味をなさなくなった。あわせて init-env から組み込みのバインディグを削除した。

ここでは束縛されない変数が現れた場合は実行時(eval 時)のエラーにしたけどプログラム解析の段階でエラーにすることもできると思う(lexical-address 内の get-address 関数の4行目)。

; Exercise 3.25
(load "r5rs.scm")
(load "define-datatype.scm")
(load "sllgen.scm")

(define empty-nameless-env
  (lambda () '()))

(define extend-nameless-env
  (lambda (vals env)
    (cons (list->vector vals) env)))

(define apply-nameless-env
  (lambda (env depth position)
    (if (null? env)
      (eopl:error 'apply-nameless-env "No binding for ~s" exp)
      (if (> depth 0)
        (apply-nameless-env (cdr env) (- depth 1) position)
        (vector-ref (car env) position)))))

(define true-value (lambda () 1))
(define false-value (lambda () 0))
(define true-value?
  (lambda (x)
    (not (= 0 x))))

(define closure
  (lambda (ids body env)
    (lambda (args)
      (if (= (length ids) (length args))
        (eval-expression body (extend-nameless-env args env))
        (eopl:error 'closure
                    "Wrong number of arguments: ~s required, but got ~s"
                    (length ids) (length args))))))

(define lexical-address
  (lambda (pgm)
    (letrec
      ((la
         (lambda (exp bs)
           (cases expression exp
             (lit-exp (datum) exp)
             (var-exp (id) (get-address id bs 0))
             (lexvar-exp (d p) exp)
             (primapp-exp (prim rands)
               (primapp-exp prim (map (lambda (x) (la x bs)) rands)))
             (if-exp (test-exp true-exp false-exp)
               (if-exp (la test-exp bs) (la true-exp bs) (la false-exp bs)))
             (let-exp (ids rands body)
               (let-exp ids
                        (map (lambda (x) (la x bs)) rands)
                        (la body (cons ids bs))))
             (proc-exp (ids body)
               (proc-exp ids (la body (cons ids bs))))
             (app-exp (rator rands)
               (app-exp (la rator bs) (map (lambda (x) (la x bs)) rands)))
             )))
       (get-address
         (lambda (var bs d)
           (cond
             ((null? bs) (var-exp var))
             ((memv var (car bs))
              (lexvar-exp d (get-pos var (car bs))))
             (else
               (get-address var (cdr bs) (+ d 1))))))
       (get-pos
         (lambda (s lst)
           (if (eqv? s (car lst))
             0
             (+ 1 (get-pos s (cdr lst))))))
       )
      (cases program pgm
        (a-program (exp)
          (a-program (la exp '())))))))

(define eval-program
  (lambda (pgm)
    (cases program pgm
      (a-program (body)
        (eval-expression body (init-env))))))

(define eval-expression
  (lambda (exp env)
    (cases expression exp
      (lit-exp (datum) datum)
      (var-exp (id)
        (eopl:error 'eval-expression "~s is not lexival variable" id))
      (lexvar-exp (d p) (apply-nameless-env env d p))
      (primapp-exp (prim rands)
        (let ((args (eval-rands rands env)))
          (apply-primitive prim args)))
      (if-exp (test-exp true-exp false-exp)
        (if (true-value? (eval-expression test-exp env))
          (eval-expression true-exp env)
          (eval-expression false-exp env)))
      (let-exp (ids rands body)
        (let ((args (eval-rands rands env)))
          (eval-expression body (extend-nameless-env args env))))
      (proc-exp (ids body)
        (closure ids body env))
      (app-exp (rator rands)
        (let ((proc (eval-expression rator env))
              (args (eval-rands rands env)))
          (apply-procval proc args)))
      )))

(define eval-rands
  (lambda (rands env)
    (map (lambda (x) (eval-rand x env)) rands)))

(define eval-rand
  (lambda (rand env)
    (eval-expression rand env)))

(define apply-primitive
  (lambda (prim args)
    (cases primitive prim
      (add-prim () (+ (car args) (cadr args)))
      (subtract-prim () (- (car args) (cadr args)))
      (mult-prim () (* (car args) (cadr args)))
      (incr-prim () (+ (car args) 1))
      (decr-prim () (- (car args) 1))
      )))

(define apply-procval
  (lambda (proc args)
    (proc args)))

(define init-env
  (lambda () (empty-nameless-env)))

(define scanner-spec-3-7
  '((white-sp
      (whitespace) skip)
    (comment
      ("%" (arbno (not #\newline))) skip)
    (identifier
      (letter (arbno (or letter digit "?"))) symbol)
    (number
      (digit (arbno digit)) number)))

(define grammar-3-7
  '((program
      (expression)
      a-program)
    (expression
      (number)
      lit-exp)
    (expression
      (identifier)
      var-exp)
    (expression
      ("[" number number "]")
      lexvar-exp)
    (expression
      (primitive "(" (separated-list expression ",") ")" )
      primapp-exp)
    (expression
      ("if" expression "then" expression "else" expression)
      if-exp)
    (expression
      ("let" (arbno identifier "=" expression) "in" expression)
      let-exp)
    (expression
      ("proc" "(" (separated-list identifier ",") ")" expression)
      proc-exp)
    (expression
      ("(" expression (arbno expression) ")")
      app-exp)
    (primitive ("+") add-prim)
    (primitive ("-") subtract-prim)
    (primitive ("*") mult-prim)
    (primitive ("add1") incr-prim)
    (primitive ("sub1") decr-prim)
    ))

(define scan&parse
  (sllgen:make-string-parser
    scanner-spec-3-7
    grammar-3-7))

(sllgen:make-define-datatypes scanner-spec-3-7 grammar-3-7)

(define run
  (lambda (string)
    (eval-program
      (lexical-address
      (scan&parse string)))))

(define read-eval-print
  (sllgen:make-rep-loop "-->" (lambda (x) (eval-program (lexical-address x)))
    (sllgen:make-stream-parser
      scanner-spec-3-7
      grammar-3-7)))

nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。