如何在Beginning Student Language中实现S-Expression求值函数?
Got it, let's work through building this evaluator step by step for Beginning Student Language (with list abbreviations). The key idea is to recursively process each S-expression, handling self-evaluating types directly and evaluating lists by checking if they're operator calls or just lists of evaluated values.
First, we'll need helper functions to handle arithmetic operations since Beginning Student doesn't have apply (which would simplify things, but we can work around it):
; Helper to sum all elements in a list (define (sum lst) (cond [(empty? lst) 0] [else (+ (first lst) (sum (rest lst)))])) ; Helper to multiply all elements in a list (define (product lst) (cond [(empty? lst) 1] [else (* (first lst) (product (rest lst)))])) ; Helper for subtraction: handles negation (- x) and multi-arg subtraction (- x y z) (define (subtract lst) (cond [(empty? lst) (error "subtract requires at least one argument")] [(empty? (rest lst)) (- (first lst))] [else (- (first lst) (sum (rest lst)))])) ; Helper for division: handles reciprocal (/ x) and multi-arg division (/ x y z) (define (divide lst) (cond [(empty? lst) (error "divide requires at least one argument")] [(empty? (rest lst)) (/ (first lst))] [else (/ (first lst) (product (rest lst)))]))
Now the main eval function. We'll structure it with a cond to check each type of S-expression:
(define (eval s) (cond ; Self-evaluating types: return them as-is [(number? s) s] [(string? s) s] [(boolean? s) s] [(image? s) s] [(empty? s) empty] ; Symbols are returned directly (unless they're the operator in a list) [(symbol? s) s] ; Handle lists: either evaluate as an operator call or a list of evaluated values [(list? s) (if (empty? s) empty (let ([op (eval (first s))] ; Evaluate the first element (could be an operator) [args (map eval (rest s))]) ; Evaluate all other elements (cond ; Arithmetic operators [(symbol=? op '+) (sum args)] [(symbol=? op '-) (subtract args)] [(symbol=? op '*) (product args)] [(symbol=? op '/) (divide args)] ; List manipulation operators [(symbol=? op 'list) args] ; args are already evaluated, just return the list [(symbol=? op 'cons) (if (not (= (length args) 2)) (error "cons needs exactly two arguments: (cons element list)") (cons (first args) (second args)))] ; If it's not a recognized operator, return the list of evaluated elements [else (cons op args)])))] ; Catch-all for unknown types [else (error (string-append "Unknown S-Expression type: " (format "~a" s)))]))
How this works:
- Self-evaluating types: Numbers, strings, booleans, images, and
emptyare returned immediately because they don't need evaluation. - Symbols: Symbols like
'xor'+are returned as-is—we only treat them as operators when they're the first element of a list. - Lists:
- We first evaluate the first element (to handle nested operators like
'(+ 2 (* 3 4))). - We evaluate all other elements in the list using
map eval. - If the evaluated first element is a recognized operator (
+,-, etc.), we apply the corresponding helper function to the evaluated arguments. - If it's not a recognized operator, we just return the list of evaluated elements (like your example
'(1 2 (+ 2 1))becomes(list 1 2 3)).
- We first evaluate the first element (to handle nested operators like
Test cases to verify:
; Your example input (eval '(1 2 (+ 2 1))) ; Returns (list 1 2 3) ; Nested arithmetic (eval '(+ 5 (* 2 3) (- 10 4))) ; Returns 5 + 6 +6 =17 ; List operations (eval '(cons 1 (list 2 (+ 3 4)))) ; Returns (list 1 2 7) ; Self-evaluating types (eval '("hello" #t empty)) ; Returns (list "hello" #t empty) ; Symbol handling (eval '(a b c)) ; Returns (list 'a 'b 'c)
Limitations to note:
- This only handles a basic set of operators—you can add more (like
modulo,max, etc.) by adding new cases to thecondin the list handling section. - There's no variable support (since your question didn't mention it), but you could extend this by adding an environment parameter to track variable bindings if needed.
内容的提问来源于stack exchange,提问作者HappyR
相关产品推荐
相关产品推荐

