Подача заявки в схеме?

Я пытаюсь написать интерпретатор для схемы. До сих пор я реализовал определение, если и некоторые арифметические выражения. Вот грамматика для моего переводчика:

<s6> -> <expr>
        | <define>

<expr> -> NUMBER
          | IDENT
          | <if>
          | <let>

<define> -> ( define IDENT <expr> )

<if> -> ( if <expr> <expr> <expr> )

<let> -> ( let ( <var_binding_list> ) <expr> )

<var_binding_list> -> ( IDENT <expr> ) <var_binding_list>
                      | ( IDENT <expr> )

Вот код, который я написал до сих пор:

(define get-operator (lambda (op-symbol)
(cond
    ((equal? op-symbol '+) +)
    ((equal? op-symbol '-) -)
    ((equal? op-symbol '*) *)
    ((equal? op-symbol '/) /)
    (else (error "s6-interpret: operator not implemented -->" op-symbol)))))

(define let-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'let) (= (length e) 3))))

(define if-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'if) (= (length e) 4))))

(define define-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'define) (symbol? (cadr e)) (= (length e) 3))))


(define get-value (lambda (var env)
(cond
    ((null? env) (error "s6-interpret: unbound variable -->" var))
    ((equal? (caar env) var) (cdar env))
    (else (get-value var (cdr env))))))


(define extend-env (lambda (var val old-env)
(cons (cons var val) old-env)))


(define repl (lambda (env)
(let* (
    (dummy1 (display "cs305> "))
    (expr (read))
    (new-env (if (define-stmt? expr)
                (extend-env (cadr expr) (s6-interpret (caddr expr) env) env)env))
    (val (if (define-stmt? expr)
                (cadr expr)
                (s6-interpret expr env)))
    (dummy2 (display "cs305: "))
    (dummy3 (display val))
    (dummy4 (newline))
    (dummy4 (newline)))
(repl new-env))))


(define s6-interpret (lambda (e env)
(cond
    ((number? e) e)
    ((symbol? e) (get-value e env))
    ((not (list? e)) (error "s6-interpret: cannot evaluate -->" e))
    ((if-stmt? e) (if (eq? (cadr e) 0) ( s6-interpret (cadddr e) env) ( s6-interpret(caddr e) env)))
    ((let-stmt? e) (apply let (map s6-interpret (cdr e))))
    (else
        (let ((operands (map s6-interpret (cdr e) (make-list (length (cdr e)) env)))
                (operator (get-operator (car e))))
            (apply operator operands))))))


(define cs305-interpreter (lambda () (repl '())))

Все, что я написал, кроме «пусть», работает нормально. дай стмт? процедура тоже работает как я хочу, но часть кода ((let-stmt? e) (apply let (map s6-interpret (cdr e)))) в s6-interpret не работает нормально, выдает ошибку что «синтаксическое ключевое слово не может использоваться в качестве выражения». Может ли кто-нибудь помочь мне с реализацией интерпретатора оператора «let», как указано в грамматике?

Спасибо


person yrazlik    schedule 23.05.2013    source источник
comment
Можете ли вы сделать репост после того, как вы скомпилируете и запустите вышеприведенное без ошибки подсчета аргументов?   -  person GoZoner    schedule 24.05.2013
comment
@GoZoner ну, на самом деле я все еще думаю о том, как реализовать оператор let, я не смог его решить. Вы имеете в виду репост после решения?   -  person yrazlik    schedule 24.05.2013
comment
Также как вы не можете подать заявку, если вы не можете подать заявку, пусть. let на самом деле просто синтаксический сахар для анонимной процедуры, поэтому вы должны сначала реализовать лямбда-вызовы, например ((lambda (x) x) 5) должен оцениваться как 5. Затем вы можете реализовать так, чтобы (let ((x 5)) x ) является синонимом этого.   -  person Sylwester    schedule 24.05.2013
comment
Вы не должны реализовывать let до реализации lambda. let не является нормальной формой, это производное выражение, которое после синтаксического преобразования оценивается как lambda.   -  person Óscar López    schedule 24.05.2013


Ответы (2)


Легко реализовать let, не беспокоясь о lambda, поскольку let просто расширяет среду и оценивает тело в новой расширенной среде. Как так:

...
((let-stmt? e)
 (let ((names (map car  (cadr e)))
       (inits (map cadr (cadr e))))
   ;; Evaluate inits in env
   (let ((vals (map (lambda (init) (s6-interpret init env)) inits)))
     ;; Extend env with names+vals
     (let ((new-env (append (map cons names vals) env)))
       ;; Eval body in new env
       (s6-interpret (caddr e) new-env)))))   ; assumes 'body' is one form...
...

Вы также можете не беспокоиться об общих вызовах функций, используя этот подход.

person GoZoner    schedule 23.05.2013
comment
хорошо, спасибо, я пытаюсь понять это сейчас, но я не уверен, оценивается ли оно как 7, когда я пишу (пусть ((x 3) (y 4)) (+ x y)). Имеет ли это? На данный момент мне кажется, что мы присваиваем значения переменным, но мы также вычисляем выражение здесь после присвоения значений? - person yrazlik; 24.05.2013
comment
Я попробовал ввести (let ((x 4) (y 3)) (+ x y)) но выдал ошибку о том, что оператор не реализован (+ x y). Можем ли мы что-нибудь с этим сделать? Спасибо - person yrazlik; 24.05.2013
comment
Вы спросили: «Мы также вычисляем выражение здесь». Возможно, вы можете поискать, где вызывается s6-interpret, так как, как вы знаете, именно здесь все вычисляется. - person GoZoner; 24.05.2013

Вы не можете apply использовать специальную форму let. Ошибка понятна: это не процедура, это синтаксис (макрос). Одним из возможных решений было бы реализовать синтаксическое преобразование на уровне оценщика, как только будет обнаружено let, преобразовать его в выражение lambda и оценить его.

Взгляните на упражнение 4.6 в SICP. найдите тему "Производные выражения". Ключевая идея здесь заключается в том, что если вы найдете такое выражение:

(let ((x 1)
      (y 2))
  (+ x y))

Вы должны преобразовать его в это выражение, которое можно легко вычислить:

((lambda (x y)
   (+ x y))
 1 2)
person Óscar López    schedule 23.05.2013