(add-to-load-path ".") (add-to-load-path "util/") (add-to-load-path "prelude/") (use-modules (environment)) (use-modules (prelude/primitives)) (use-modules (util/alist)) (define (tagged? expr tag) (if (pair? expr) (eq? (car expr) tag) #f)) ;;; self-evaluating (define (self-evaluating? expr) (or (number? expr) (string? expr) (bool? expr))) (define variable? symbol?) ;;; if-else (define (make-if predicate consequent alternative) (list 'if predicate consequent alternative)) (define (if-else? expr) (tagged? expr 'if)) (define (if-predicate expr) (cadr expr)) (define (if-consequent expr) (caddr expr)) (define (if-alternative expr) (if (not (null? (cdddr expr))) (cadddr expr) 'false)) ;;; cond forms (define (cond-form? expr) (tagged? expr 'cond)) (define (cond-clauses expr) (cdr expr)) (define (cond-predicate clause) (car clause)) (define (cond-consequent clause) (cadr clause)) (define (cond-else? clause) (tagged? clause 'else)) (define (last-clause? clauses) (null? (cdr clauses))) (define (make-cond clauses) (cons 'cond clauses)) (define (cond->if expr) (let ([clauses (cond-clauses expr)]) (cond [(cond-else? (car clauses)) (cond-consequent (car clauses))] [(last-clause? clauses) (make-if (cond-predicate (car clauses)) (cond-consequent (car clauses)) 'false)] [else (make-if (cond-predicate (car clauses)) (cond-consequent (car clauses)) (cond->if (make-cond (cdr clauses))))]))) ;;; function application (define (function-application? expr) (pair? expr)) (define (operator expr) (car expr)) (define (operands expr) (cdr expr)) (define (no-operands? expr) (null? expr)) (define (list-of-values ls env) (map (lambda (l) (eval-expr l env)) ls)) ;;; quoted expressions (define (quote-form? expr) (tagged? expr 'quote)) (define (quotation-text expr) (cadr expr)) ;;; assignment (define (assignment? expr) (tagged? expr 'set!)) (define (assignment-name expr) (cadr expr)) (define (assignment-value expr) (caddr expr)) ;;; definition (define (definition? expr) (tagged? expr 'define)) (define (definition-name expr) (cadr expr)) (define (definition-value expr) (caddr expr)) ;;; lambda (define (lambda-form? expr) (tagged? expr 'lambda)) (define (lambda-params expr) (cadr expr)) (define (lambda-body expr) (cddr expr)) (define (make-lambda params body) (cons 'lambda (cons params body))) ;;; begin (define (begin-form? expr) (tagged? expr 'begin)) (define (begin-actions begin-form) (cdr begin-form)) (define (last-action? actions) (null? (cdr actions))) (define (make-begin actions) (cons 'begin actions)) (define (sequence->expr actions) (cond [(null? actions) '()] [(last-action? actions) (car actions)] [else (make-begin actions)])) ;;; let (define (let-form? expr) (tagged? expr 'let)) (define (let-bindings expr) (cadr expr)) (define (let-body expr) (cddr expr)) (define (let-binding-variables bindings) (map car bindings)) (define (let-binding-values bindings) (map cadr bindings)) (define (let->lambda expr) (let ([bindings (let-bindings expr)]) (make-lambda (let-binding-variables bindings) (let-body expr)))) (define (eval-expr expr env) (cond [(self-evaluating? expr) expr] [(variable? expr) (lookup-variable-value expr env)] [(if-else? expr) (eval-if expr env)] [(begin-form? expr) (eval-sequence (begin-actions expr) env)] [(lambda-form? expr) (make-lambda (lambda-params expr) (lambda-body expr))] [(let-form? expr) (eval-let expr env)] [(assignment? expr) (eval-assignment expr env)] [(definition? expr) (eval-definition expr env)] [(cond-form? expr) (eval-cond expr env)] [(quote-form? expr) (quotation-text expr)] [(function-application? expr) (eval-function-application expr env)])) (define (eval-if expr env) (if (true? (eval-expr (if-predicate expr) env)) (eval-expr (if-consequent expr) env) (eval-expr (if-alternative expr) env))) (define (eval-cond expr env) (eval-expr (cond->if expr) env)) (define (eval-sequence exprs env) (cond [(last-action? exprs) (eval-expr (car exprs) env)] [else (begin (eval-expr (car exprs) env) (eval-sequence (cdr exprs) env))])) (define (eval-let expr env) (eval-function-application (cons (let->lambda expr) (let-binding-values (let-bindings expr))) env)) (define (eval-assignment expr env) (set-variable-value! (assignment-name expr) (eval-expr (assignment-value expr) env) env)) (define (eval-definition expr env) (define-variable! (definition-name expr) (eval-expr (definition-value expr) env) env)) (define (eval-function-application expr env) (let ([proc (operator expr)] [args (list-of-values (operands expr) env)]) (cond [(primitive? proc) (apply-primitive-proc proc args)] [else (let ([compound-proc (eval-expr proc env)]) (eval-sequence (lambda-body compound-proc) (extend-env (lambda-params compound-proc) args env)))]))) (define (primitive? proc) (is-elem-assoc-list proc primitives)) (define (apply-primitive-proc proc args) (let ([p (lookup-assoc-list proc primitives)]) (apply p args))) (define (apply-expr proc args) (cond [(primitive? proc) (apply-primitive-proc proc args)] [else 'false])) (define the-global-env (setup-environment)) (define input-prompt ";;; CIRCLE INPUT ") (define output-prompt ";;; CIRCLE OUTPUT ") (define (driver-loop) (begin (newline) (display input-prompt) (newline) (let ([input (read)]) (let ([output (eval-expr input the-global-env)]) (begin (display output-prompt) (newline) (show-lisp-expr output) (newline) (driver-loop)))))) (define (show-lisp-expr object) (cond [(tagged? object 'lambda) (display "#")] [else (display object)]))