3

我正在尝试学习方案并尝试在方案中实现 let* 的解释器。这是语法:

<s6> -> <expr>                   
       | <define>
<expr> -> NUMBER | IDENT | <if> | <let> | <letstar> | <lambda> | <application>
<define> -> ( define IDENT <expr> )
<if> -> ( if <expr> <expr> <expr> )
<let> -> ( let ( <var_binding_list> ) <expr> )
<letstar> -> ( let* ( <var_binding_list> ) <expr> )
<lambda> -> ( lambda ( <formal_list> ) <expr> )
<application> -> ( <operator> <operand_list> )
<operator> -> <built_in_operator> | <lambda> | IDENT
<built_in_operator> -> + | * | - | /
<operand_list> -> <expr> <operand_list> | empty
<var_binding_list> -> ( IDENT <expr> ) <var_binding_list> | ( IDENT <expr> )
<formal_list> -> IDENT <formal_list> | IDENT

我之前已经学会了如何实现 let ,这里是:

(define let-stmt? (lambda (e)
(and (list? e) (equal? (car e) 'let) (= (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 s6-interpret (lambda (e env)     //thanks to GoZooner
(cond
    ((number? e) e)
    ((symbol? e) (get-value e env))
    ((not (list? e)) (error "s6-interpret: cannot evaluate -->" e))

    ((let-stmt? e)
        (let ((names (map car  (cadr e)))
                (inits (map cadr (cadr e))))

        (let ((vals (map (lambda (init) (s6-interpret init env)) inits)))

        (let ((new-env (append (map cons names vals) env)))

        (s6-interpret (caddr e) new-env)))))

如何修改 let 的解释器以便我可以为 let* 编写解释器?任何人都可以帮忙吗?

谢谢

4

3 回答 3

2

这个问题最近被问过好几次了,在 Scheme 问题列表中向下滚动。这里是它的要点:let*是一个句法转换,在SICP中阅读更多关于这个主题的信息,查找标题为“派生表达式”的部分。这种情况的关键思想是,每当您的评估者找到这样的表达式时:

(let* ((a 10)
       (b (+ 10 a)))
  (+ a b))

...您可以直接将其转换为等效的一系列嵌套lambda应用程序,可以像这样轻松评估:

((lambda (a)
   ((lambda (b)
      (+ a b))
    (+ 10 a)))
 10)

或者,您可以执行一个中间步骤,首先将 alet*转换为一系列嵌套let的 s,然后评估它们 - 如果您已经实现了let特殊形式,这很有用。上面的相同示例如下所示:

(let ((a 10))
  (let ((b (+ 10 a)))
    (+ a b)))

当然,首先你必须知道如何评估一个lambda表格。这里的重点是,两者let都是let*特殊形式(只不过是语法糖),它们不遵循相同的评估模型,例如程序应用程序,并且需要在评估者级别进行特殊处理 - 在这种情况下,一种语法转换,它产生我们知道如何评估的不同表达式。

于 2013-05-30T19:05:29.877 回答
1

我知道:

(let* ((a ...) (b ...) (c ...)) body ...)

相当于:

(let ((a ...))
  (let ((b ...))
    (let ((c ...))
      body ...)))

(参见R5RS,第 44 页,(define-syntax let* ...))。现在,鉴于此,并且知道:

  (let ((a ...)) body ...)

相当于:

  ((lambda (a) body ...) ...)

let*我上面显示的“扩展”变为:

  ((lambda (a)
     ((lambda (b)
        ((lambda (c)
           body ...)
          <c-init>))
      <b-init>))
   <a-init>)
于 2013-05-30T22:57:05.990 回答
1

R5RS,第 7.3 节:

(define-syntax let*
  (syntax-rules ()
    ((let* () body1 body2 ...)
      (let () body1 body2 ...))
    ((let* ((name1 val1) (name2 val2) ...) body1 body2 ...)
      (let ((name1 val1))
        (let* ((name2 val2) ...)
          body1 body2 ...)))))
于 2013-05-30T20:58:34.263 回答