SICP/ex-4_01-xx.scm

166 lines
4.9 KiB
Scheme
Raw Normal View History

2021-01-14 13:35:46 +01:00
(load "util.scm")
2021-01-15 20:38:24 +01:00
(load "misc/evaluator.scm")
2021-01-14 13:35:46 +01:00
2021-01-15 20:38:24 +01:00
(display "\nex-4.1 - list-of-values\n")
(define (list-of-values-left-to-right exps env)
(if (no-operands? exps)
'()
(let ((first (eval (first-operand exps) env)))
(let ((rest ((list-of-values (rest-operands exps) env))))
(cons first rest)))))
(define (list-of-values-right-to-left exps env)
(if (no-operands? exps)
'()
(let ((rest ((list-of-values (rest-operands exps) env))))
(let ((first (eval (first-operand exps) env)))
(cons first rest)))))
(display "[done]\n")
2021-01-16 11:19:25 +01:00
(display "\nex-4.2 - explicite-call\n")
2021-01-15 20:38:24 +01:00
2021-01-16 11:19:25 +01:00
; Louis's plan does not work because the implementation would treat assignments
; and definitions as applications. That means define and set! would no longer be
; special forms.
(define (application?-call exp) (tagged-list exp 'call))
(define (operator-call exp) (cadr exp))
(define (operands-call exp) (cddr exp))
(display "[done]\n")
(display "\nex-4.3 - data-directed-eval\n")
(define *eval-table* (make-hash-table))
(define (put op proc)
(hash-table/put! *eval-table* (list op) proc))
(define (get op)
(hash-table/get *eval-table* (list op) #f))
(define (install-eval-package)
(put 'quote (lambda (exp env) (text-of-quotation exp)))
(put 'set! eval-assignment)
(put 'define eval-definition)
(put 'if eval-if)
(put 'lambda
(lambda (exp env)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env)))
(put 'begin (lambda (exp env) (eval-sequence (begin-actions exp) env)))
(put 'cond (lambda (exp env) (eval (cond->if exp) env)))
2021-01-17 18:16:20 +01:00
(put 'let (lambda (exp env) (eval (let->lambda exp) env)))
(put 'and (lambda (exp env) (eval-and (clauses exp) env)))
(put 'or (lambda (exp env) (eval-or (clauses exp) env)))
2021-01-16 11:19:25 +01:00
(display "[install-eval-package]\n")
'done)
(install-eval-package)
(define (eval exp env)
2021-01-17 18:16:20 +01:00
; (display "(EVAL ") (display exp) (display ")") (newline)
2021-01-16 11:19:25 +01:00
(cond
((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
2021-01-17 18:16:20 +01:00
((and (not (null? exp)) (get (car exp)))
((get (car exp)) exp env))
2021-01-16 11:19:25 +01:00
((application? exp)
(apply (eval (operator exp) env)
(list-of-values (operands exp) env)))
(else (error "Unknown expression type -- EVAL" exp))))
(display "[done]\n")
2021-01-17 18:16:20 +01:00
(display "\nex-4.4 - and/or\n")
(define (clauses exp) (cdr exp))
(define (no-clauses? exp) (null? exp))
(define (first-clause exp) (car exp))
(define (rest-clauses exp) (cdr exp))
(define (eval-and exp env)
(if (no-clauses? exp)
#t
(if (true? (eval (first-clause exp) env))
(eval-and (rest-clauses exp) env)
#f)))
(define (eval-or exp env)
(if (no-clauses? exp)
#f
(if (true? (eval (first-clause exp) env))
#t
(eval-or (rest-clauses exp) env))))
(define (true? a) a)
(assert (eval '(or) '()) #f)
(assert (eval '(and) '()) #t)
(assert (eval '(and 0 0 0 #f) '()) #f)
(assert (eval '(or #f #f #t) '()) #t)
(display "\nex-4.5 - modified-cond\n")
; Exercise 4.5. Scheme allows an additional syntax for cond clauses, (<test> =>
; <recipient>).
; If <test> evaluates to a true value, then <recipient> is evaluated. Its value
; must be a procedure of one argument; this procedure is then invoked on the
; value of the <test>, and the result is returned as the value of the cond
; expression. For example
; (cond ((assoc 'b '((a 1) (b 2))) => cadr)
; (else false))
; returns 2. Modify the handling of cond so that it supports this extended syntax.
(define (cond-test exp) (car exp))
(define (cond-recipient exp) (caddr exp))
(define (cond-test-recipient-clause? exp)
(eq? (cadr exp) '=>))
(define (expand-clauses clauses)
(if (null? clauses)
'false ; no else clause
(let ((first (car clauses))
(rest (cdr clauses)))
(cond
((cond-else-clause? first)
(if (null? rest)
(sequence->exp (cond-actions first))
(error "ELSE clause isn't last -- COND->IF"
clauses)))
((cond-test-recipient-clause? first)
(let ((test-evaluated (eval (cond-test exp) env)))
(if test-evaluated
(eval (list (cond-recipient exp) test-evaluated) env)
(expand-clauses rest))))
(else
(make-if (cond-predicate first)
(sequence->exp (cond-actions first))
(expand-clauses rest)))))))
2021-01-16 11:19:25 +01:00
2021-01-17 18:16:20 +01:00
(display "[done]\n")
(display "\nex-4.6 - let-expression\n")
(define (let->lambda exp) 0)
; (let ((<var1> <exp1>) ... (<varn> <expn>))
; <body>)
;
; ((lambda (<var1> ... <varn>)
; <body>)
; <exp1>
;
; <expn>)
; Implement a syntactic transformation let->combination that reduces evaluating
; let expressions to evaluating combinations of the type shown above, and add the
; appropriate clause to eval to handle let expressions
(display "\nex-4.7")
2021-01-14 13:35:46 +01:00