【问题标题】:Implementing an interpreter for "if" statement in scheme为方案中的“if”语句实现解释器
【发布时间】:2013-05-23 18:02:44
【问题描述】:

我正在尝试在方案中实现解释器。现在我实现了它的一部分,但我遇到了“if”语句的问题。语法如下:

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

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

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

<if> -> ( if <expr> <expr> <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 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) (map s6-interpret (cadddr e)) (map s6-interpret(caddr 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 '())))

define 语句运行良好。我的代码还包括一些基本数学运算符的实现,您可以忽略它们。我的问题是,我实现的“if”语句没有像我预期的那样工作。当我写“(if 1(+ 2 5)9)”时,它会打印出(+ 2 5),但实际上我希望它打印出7,即2+5。我认为我的递归存在问题。谁能帮我解决这个问题?

谢谢

【问题讨论】:

    标签: scheme interpreter


    【解决方案1】:

    您为 if 语句编写的代码永远不会触发,因为 if 语句是长度为 4 的列表,而不是 3:

    (define if-stmt? (lambda (e)
      (and (list? e)
           (equal? (car e) 'if)
           (= (length e) 3))))
    
    
    > (length '(if condition then-clause else-clause))
    4
    > (if-stmt? '(if condition then-clause else-clause))
    #f
    

    接受任何以符号“if”开头的列表作为 if 语句可能更有意义。如果它没有合法的长度,那只是意味着它是一个 broken if 语句,而不是完全是别的东西(除非你编写解释器的语言对于 Lisp 来说是不寻常的尊重)。

    您的递归确实也有问题,因为在这种情况下您没有使用它。当if-stmt?触发器,您不会再次调用 s6-interpret。以下将更接近正确:

    ((if-stmt? e)
     (s6-interpret
      (if (eq? (cadr e) 0)
         (cadddr e)
         (caddr e))
      env))
    

    请注意,您的实现还存在其他违规行为,包括 if 语句。例如,“0”评估为假是不合常规的,而#f 评估为真当然是非常不合常规的。

    检查 Scheme 实现的实际作用,看看哪些是常规/正确的。您也可以参考R5RS,它相对较短,对于语言规范来说是可读的。

    关于代码易读性的一些提示:

    您应该使用常规缩进。这将使您的代码更易于阅读。如果您使用的是 Scheme-aware 编辑器,该编辑器可能会为您提供帮助。例如,在 DrRacket 中,只需在一行的开头按“制表符”,该行就会为您修复。您需要根据需要插入换行符。

    Scheme 有专门用于定义函数的语法。用它。您可能已经被告知可以通过将 lambda 绑定到符号名称来实现所有内容——函数并不特殊。这是一个重要的理论点,但在实践中这样做并不是一个好主意。以下内容本质上是等价的,但后者更短且更易于阅读。

    (define f (lambda (a b) (+ a b)))
    (define (f a b) (+ a b))
    

    【讨论】:

    • 哦,你说得对,谢谢,但现在我正在编辑这个不是我真正想问的问题。但是感谢您对此提出警告
    • 好吧,我解决了,但我也会考虑您的建议。谢谢
    猜你喜欢
    • 2014-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-08-18
    • 2015-04-03
    相关资源
    最近更新 更多