【问题标题】:Applying "let" in scheme?在方案中应用“让”?
【发布时间】:2013-05-19 08:00:48
【问题描述】:

我正在尝试为方案编写解释器。到目前为止,我实现了定义、if 和一些算术表达式。这是我的解释器的语法:

<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?程序也可以按我的意愿工作,但是 s6-interpret 中的代码部分 ((let-stmt?e) (apply let (map s6-interpret (cdr e)))) 不能正常工作,它给了我一个错误说即“句法关键字不得用作表达式”。谁能帮我实现语法中给出的“let”语句的解释器?

谢谢

【问题讨论】:

  • 在你得到上述编译和运行后,你能重新发布没有参数计数错误吗?
  • @GoZoner 好吧,其实我还在思考如何实现 let 语句,我无法解决。你的意思是解决之后再发?
  • 就像不能申请就不能申请一样。 let 实际上只是匿名过程的语法糖,因此您应该首先实现 lambda 调用,例如 ((lambda (x) x) 5) 应该评估为 5。然后您可以实现 (let ((x 5)) x ) 是它的同义词。
  • 你不应该实现let之前实现lambdalet 不是普通形式,它是一个派生表达式,在语法转换后被评估为 lambda

标签: scheme interpreter let


【解决方案1】:

你不能apply 特殊形式let。错误很明显:它不是过程,而是语法(宏)。一种可能的解决方案是在求值者级别实现句法转换,一旦检测到let,将其转换为lambda 表达式并求值。

查看SICP 中的练习4.6,查找“派生表达式”主题。这里的关键思想是,如果你找到这样的表达式:

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

你必须把它转换成这个表达式,可以很容易地计算:

((lambda (x y)
   (+ x y))
 1 2)

【讨论】:

    【解决方案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...
    ...
    

    您还可以避免担心使用这种方法的一般函数调用。

    【讨论】:

    • 嗯,谢谢,我现在正试图理解它,但我不确定当我写 (let ((x 3) (y 4)) (+ xy)) 时它是否计算为 7 .可以?现在在我看来,我们正在为变量赋值,但我们是否也在赋值后计算这里的表达式?
    • 我尝试了输入 (let ((x 4) (y 3)) (+ x y)),但它给出了一个错误,指出运算符未实现 (+ x y)。我们能对此做些什么吗?谢谢
    • 你问'我们是否也计算这里的表达式'。也许您可以查找调用 s6-interpret 的位置,因为如您所知,这是计算内容的位置。
    猜你喜欢
    • 1970-01-01
    • 2018-05-17
    • 2013-03-21
    • 2011-09-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-26
    相关资源
    最近更新 更多