;; This file contains excerpts from the textbook Concrete ;; Abstractions: An Introduction to Computer Science Using Scheme, by ;; Max Hailperin, Barbara Kaiser, and Karl Knight, Copyright (c) 1998 ;; by Brooks/Cole Publishing Company. This file may not be reproduced ;; or redistributed other than for use with that textbook. ;; stuff from chapter 7: (define make-pattern/action (lambda (pattern action) (cons pattern action))) (define pattern car) (define action cdr) (define matches? ; version resulting from doing exercise 7.29 (lambda (pattern question) (cond ((null? pattern) (null? question)) ((null? question) #F) ((equal? (car pattern) '_) (matches? (cdr pattern) (cdr question))) ((list? (car pattern)) (if (member (car question) (car pattern)) (matches? (cdr pattern) (cdr question)) #F)) ((equal? (car pattern) '...) #T) ((equal? (car pattern) (car question)) (matches? (cdr pattern) (cdr question))) (else #F)))) (define substitutions-in-to-match ; version resulting from doing exercise 7.30 (lambda (pattern question) (cond ((null? pattern) (if (null? question) '() (error "substitutions-in-to-match without a match"))) ((null? question) (error "substitutions-in-to-match without a match")) ((equal? (car pattern) '_) (cons (car question) (substitutions-in-to-match (cdr pattern) (cdr question)))) ((list? (car pattern)) (if (member (car question) (car pattern)) (cons (car question) (substitutions-in-to-match (cdr pattern) (cdr question))) (error "substitutions-in-to-match without a match"))) ((equal? (car pattern) '...) (list question)) ((equal? (car pattern) (car question)) (substitutions-in-to-match (cdr pattern) (cdr question))) (else (error "substitions-in-to-match without a match"))))) (define all-are (lambda (pred) (lambda (l) (cond ((null? l) #t) ((pred (car l)) ((all-are pred) (cdr l))) (else #f))))) ;; stuff from chapter 8: (define look-up-value (lambda (name) (cond ((equal? name '+) +) ((equal? name '*) *) ((equal? name '-) -) ((equal? name '/) /) (else (error "Unrecognized name" name))))) ;; new stuff, from chapter 10: (define keyword? (lambda (x) (or (equal? x 'if) (equal? x 'lambda) (equal? x 'quote)))) (define name? (lambda (x) (and (symbol? x) (not (keyword? x))))) (define read-eval-print-loop (lambda () (display ";Enter Micro-Scheme expression:") (newline) (let ((expression (read))) (let ((value (evaluate (parse expression)))) (display ";Micro-Scheme value: ") (write value) (newline))) (read-eval-print-loop))) (define parse (lambda (expression) (define loop (lambda (p/a-list) (cond ((null? p/a-list) (error "invalid expression" expression)) ((matches? (pattern (car p/a-list)) expression) (apply (action (car p/a-list)) (substitutions-in-to-match (pattern (car p/a-list)) expression))) (else (loop (cdr p/a-list)))))) ;end of loop (cond ((name? expression) ;start of main parse procedure (make-name-ast expression)) ((or (number? expression) (string? expression) (boolean? expression)) (make-constant-ast expression)) ((list? expression) (loop micro-scheme-parsing-p/a-list)) (else (error "invalid expression" expression))))) (define micro-scheme-parsing-p/a-list (list (make-pattern/action '(if _ _ _) (lambda (test if-true if-false) (make-conditional-ast (parse test) (parse if-true) (parse if-false)))) (make-pattern/action '(lambda _ _) (lambda (parameters body) (if (and (list? parameters) ((all-are name?) parameters)) (make-abstraction-ast parameters (parse body)) (error "invalid expression" (list 'lambda parameters body))))) (make-pattern/action '(quote _) (lambda (value) (make-constant-ast value))) (make-pattern/action '(...) ; note that this *must* come last (lambda (operator&operands) (let ((asts (map parse operator&operands))) (make-application-ast (car asts) (cdr asts))))))) (define evaluate (lambda (ast) (ast 'evaluate))) (define substitute-for-in (lambda (value name ast) ((ast 'substitute-for) value name))) (define make-name-ast (lambda (name) (define the-ast (lambda (message) (cond ((equal? message 'evaluate) (look-up-value name)) ((equal? message 'substitute-for) (lambda (value name-to-substitute-for) (if (equal? name name-to-substitute-for) (make-constant-ast value) the-ast))) (else (error "unknown operation on a name AST" message))))) the-ast)) (define make-constant-ast (lambda (value) (define the-ast (lambda (message) (cond ((equal? message 'evaluate) value) ((equal? message 'substitute-for) (lambda (value name) the-ast)) (else (error "unknown operation on a constant AST" message))))) the-ast)) (define make-conditional-ast (lambda (test-ast if-true-ast if-false-ast) (lambda (message) (cond ((equal? message 'evaluate) (if (evaluate test-ast) (evaluate if-true-ast) (evaluate if-false-ast))) ((equal? message 'substitute-for) (lambda (value name) (make-conditional-ast (substitute-for-in value name test-ast) (substitute-for-in value name if-true-ast) (substitute-for-in value name if-false-ast)))) (else (error "unknown operation on a conditional AST" message)))))) (define make-application-ast (lambda (operator-ast operand-asts) (lambda (message) (cond ((equal? message 'evaluate) (let ((procedure (evaluate operator-ast)) (arguments (map evaluate operand-asts))) (apply procedure arguments))) ((equal? message 'substitute-for) (lambda (value name) (make-application-ast (substitute-for-in value name operator-ast) (map (lambda (operand-ast) (substitute-for-in value name operand-ast)) operand-asts)))) (else (error "unknown operation on an application AST" message)))))) (define make-abstraction-ast (lambda (parameters body-ast) (define the-ast (lambda (message) (cond ((equal? message 'evaluate) (make-procedure parameters body-ast)) ((equal? message 'substitute-for) (lambda (value name) (if (member name parameters) the-ast (make-abstraction-ast parameters (substitute-for-in value name body-ast))))) (else (error "unknown operation on an abstraction AST" message))))) the-ast)) (define make-procedure (lambda (parameters body-ast) (lambda arguments (define loop (lambda (parameters arguments body-ast) (cond ((null? parameters) (if (null? arguments) (evaluate body-ast) (error "too many arguments"))) ((null? arguments) (error "too few arguments")) (else (loop (cdr parameters) (cdr arguments) (substitute-for-in (car arguments) (car parameters) body-ast)))))) (loop parameters arguments body-ast))))