我正在尝试在方案中实现解释器。现在我实现了它的一部分,但我遇到了“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”语句不能像我期望的那样工作。当我写“(如果1(+ 2 5)9)”它打印出来(+ 2 5),但实际上我想要打印出7,即2 + 5。我认为我的递归存在问题。任何人都可以帮我这个吗?
谢谢
答案 0 :(得分:3)
你为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语句开头的列表可能更有意义。如果它没有合法的长度,那就意味着它是一个破碎的 if语句,而不是它完全不同的东西(除非你正在编写一个解释器的语言对于Lisp来说是不寻常的)方面)。
你的递归确实也有问题,因为在这种情况下你没有使用它。当if-stmt?触发器,你不是再次调用s6-interpre。以下内容更接近正确:
((if-stmt? e)
(s6-interpret
(if (eq? (cadr e) 0)
(cadddr e)
(caddr e))
env))
请注意,您的实现还存在其他违规行为,包括if语句。例如,“0”评估为假是非常规的,而且#f评估为真的非常传统。
检查Scheme实现的实际内容,以查看传统/正确的内容。您还可以参考R5RS,它对于语言规范而言相对较短且可读。
关于代码易读性的一些提示:
你应该使用传统的缩进。这将使您的代码更易于阅读。如果您正在使用支持Scheme的编辑器,编辑器可能会帮助您解决此问题。例如,在DrRacket中,只需在行的开头按“tab”,此行就会为您修复。您需要根据需要插入换行符。
Scheme具有特别用于定义函数的语法。用它。你可能已经教过你可以通过将lambda绑定到符号名来实现所有东西 - 函数并不特殊。这是一个重要的理论观点,但在实践中这样做并不是一个好主意。以下内容基本相同,但后者更短,更易于阅读。
(define f (lambda (a b) (+ a b)))
(define (f a b) (+ a b))