球拍:实现功能(eval t)

racket: implement function (eval t)

我正在尝试实现一个执行以下操作的函数 (eval t):

示例:

(eval '(2 * (1 + 2))) -> 6

(eval '((3 - (4 / 2)) * 2) -> 2

我目前拥有的是:

(define (inner lst)
  ((cond
     ((equal? (second lst) '+) +)
     ((equal? (second lst) '-) -)
     ((equal? (second lst) '*) *)
     ((equal? (second lst) '/) /))
   (first lst) (third lst)))


(define (eval t)
  (cond
    ((and (number? (first t)) (number? (third t))) (inner t))
    ((list? (third t)) (eval `(,(first t) ,(second t) ,(inner (third t)))))
    ((list? (first t)) (eval `(,(inner (first t)) ,(second t) ,(third t))))))

适用于:

(eval '(1 + (1 + 2))) -> 4

(eval '((1 + 1) + (2 + 2))) -> 6

但它不适用于以下情况:

(eval '((1 + 1) + (1 + (1 + 1))))

任何帮助将不胜感激!

这里的诀窍是理解表达式可以采用两种形式:原始数字数据或包含操作的列表。作为伪语法,这意味着每个表达式必须符合以下结构:

expression = number
           | ( expression operator expression )

operator   = +
           | -
           | *
           | /

这意味着 eval 函数必须能够处理 任一 类型的表达式,因此所有这些都应该有效:

(eval 7)             ; => 7
(eval '(1 + 6))      ; => 7
(eval '((2 * 3) + 1) ; => 7

从中可以得出两点:

  1. eval 函数应该能够处理原始数字,而不仅仅是包含运算符的列表。
  2. 只有两种情况需要在 eval 函数中处理。

这意味着 eval 可能应该采用如下形式:

; eval : expression? -> number?
(define (eval expr)
  (cond
    [(number? x) ???]
    [else        ???]))

您实施 eval 的许多不同案例太复杂,没有必要。您不需要检查列表的结构,因为它始终需要以完全相同的方式进行评估:eval 左侧,然后 eval 右侧,然后将两侧与操作结合在一起在中间。之所以可行,是因为如果 eval 可以处理数字,那么 (eval 3) 之类的东西就可以正常工作。

这听起来像是一道作业题,所以我不会透露具体的实现方式,但希望这足以为您指明正确的方向。