2013-05-23 2 views
1

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

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

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

Спасибо

+0

Можете ли вы перекомпостировать после того, как вы получите выше, чтобы скомпилировать и запустить без ошибки счетчика аргументов? – GoZoner

+0

@GoZoner хорошо, на самом деле я все еще думаю о том, как реализовать оператор let, я не мог его решить. Вы имеете в виду перепрограммирование после его решения? – yrazlik

+1

Так же, как вы не можете подать заявку, если вы не можете применить let. let на самом деле просто синтаксический сахар для анонимной процедуры, поэтому сначала вы должны реализовать лямбда-вызовы, например ((lambda (x) x) 5), чтобы оценить значение 5. Тогда вы можете реализовать так, чтобы (let ((x 5)) x) является синонимом этого. – Sylwester

ответ

1

Это легко осуществить 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... 
... 

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

+0

Хорошо, спасибо, я пытаюсь понять это сейчас, но я не уверен, оценивает ли он 7, когда я пишу (let ((x 3) (y 4)) (+ x y)). Имеет ли это? На данный момент мне кажется, что мы присваиваем значения переменным, но мы также вычисляем выражение здесь после назначения значений? – yrazlik

+0

Я попробовал вход (пусть ((x 4) (y 3)) (+ x y)), но он дал ошибку, говоря, что оператор не реализован (+ x y). Можем ли мы что-нибудь сделать? Спасибо – yrazlik

+0

Вы спросили: «Мы также вычисляем выражение здесь». Возможно, вы можете искать, где вызывается 's6-interp'', поскольку, как вы знаете, это то, где вычисляется материал. – GoZoner

4

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

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

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

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

((lambda (x y) 
    (+ x y)) 
1 2) 
Смежные вопросы