aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJacques Comeaux <jacquesrcomeaux@protonmail.com>2023-10-26 20:30:16 -0500
committerJacques Comeaux <jacquesrcomeaux@protonmail.com>2023-10-26 20:30:16 -0500
commit0fabec2500cf07fc9c9fc39672340bdff70affb7 (patch)
tree08ed20e0e28162775812e25ff47fe79833fa47d0
parent3f7404aad0301123e490d6eb6da5591cae96a7c9 (diff)
Add chapter 4 part 2
-rw-r--r--chap4/part2.rkt702
1 files changed, 702 insertions, 0 deletions
diff --git a/chap4/part2.rkt b/chap4/part2.rkt
new file mode 100644
index 0000000..fe19b76
--- /dev/null
+++ b/chap4/part2.rkt
@@ -0,0 +1,702 @@
+#lang sicp
+(#%require (only racket/base print-as-expression print-mpair-curly-braces))
+(print-as-expression #f)
+(print-mpair-curly-braces #f)
+
+;; Chapter 4
+;; Metalinguistic Abstraction
+
+;; 4.2
+;; Variations on a Scheme -- Lazy Evaluation
+
+;; Normal Order and Applicative Order
+
+(#%provide eval)
+(define (eval exp env)
+ (cond
+ ((self-evaluating? exp) exp)
+ ((variable? exp) (lookup-variable-value exp env))
+ ((quoted? exp) (list-rep (text-of-quotation exp) env))
+ ((assignment? exp) (eval-assignment exp env))
+ ((definition? exp) (eval-definition exp env))
+ ((if? exp) (eval-if exp env))
+ ((lambda? exp)
+ (make-procedure
+ (lambda-parameters exp)
+ (lambda-body exp)
+ env))
+ ((begin? exp)
+ (eval-sequence (begin-actions exp) env))
+ ((cond? exp) (eval (cond->if exp) env))
+ ((let? exp) (eval (let->combination exp) env))
+ ((application? exp)
+ (apply-
+ (actual-value (operator exp) env)
+ (operands exp)
+ env))
+ (else
+ (error "Unknown expression type -- EVAL" exp))))
+
+(define (apply- procedure arguments env)
+ (cond
+ ((primitive-procedure? procedure)
+ (apply-primitive-procedure
+ procedure
+ (list-of-arg-values arguments env)))
+ ((compound-procedure? procedure)
+ (eval-sequence
+ (procedure-body procedure)
+ (extend-environment
+ (procedure-parameters procedure)
+ (list-of-delayed-args arguments env)
+ (procedure-environment procedure))))
+ (else
+ (error "Unknown procedure type -- APPLY" procedure))))
+
+(define (eval-if exp env)
+ (if (true? (actual-value (if-predicate exp) env))
+ (eval (if-consequent exp) env)
+ (eval (if-alternative exp) env)))
+
+(define (eval-sequence exps env)
+ (cond
+ ((last-exp? exps) (eval (first-exp exps) env))
+ (else
+ (eval (first-exp exps) env)
+ (eval-sequence (rest-exps exps) env))))
+
+(define (eval-assignment exp env)
+ (set-variable-value!
+ (assignment-variable exp)
+ (eval (assignment-value exp) env)
+ env)
+ 'ok)
+
+(define (eval-definition exp env)
+ (define-variable!
+ (definition-variable exp)
+ (eval (definition-value exp) env)
+ env)
+ 'ok)
+
+(define (self-evaluating? exp)
+ (cond
+ ((number? exp) true)
+ ((string? exp) true)
+ (else false)))
+
+(define (variable? exp) (symbol? exp))
+
+(define (quoted? exp)
+ (tagged-list? exp 'quote))
+
+(define (text-of-quotation exp) (cadr exp))
+
+(define (tagged-list? exp tag)
+ (if (pair? exp)
+ (eq? (car exp) tag)
+ false))
+
+(define (assignment? exp)
+ (tagged-list? exp 'set!))
+
+(define (assignment-variable exp) (cadr exp))
+
+(define (assignment-value exp) (caddr exp))
+
+(define (definition? exp)
+ (tagged-list? exp 'define))
+
+(define (definition-variable exp)
+ (if (symbol? (cadr exp))
+ (cadr exp)
+ (caadr exp)))
+
+(#%provide definition-value)
+(define (definition-value exp)
+ (if (symbol? (cadr exp))
+ (caddr exp)
+ (make-lambda
+ (cdadr exp)
+ (cddr exp))))
+
+(define (lambda? exp) (tagged-list? exp 'lambda))
+
+(define (lambda-parameters exp) (cadr exp))
+
+(#%provide lambda-body)
+(define (lambda-body exp) (cddr exp))
+
+(define (make-lambda parameters body)
+ (cons 'lambda (cons parameters body)))
+
+(define (if? exp) (tagged-list? exp 'if))
+
+(define (if-predicate exp) (cadr exp))
+
+(define (if-consequent exp) (caddr exp))
+
+(define (if-alternative exp)
+ (if (not (null? (cdddr exp)))
+ (cadddr exp)
+ 'false))
+
+(define (make-if predicate consequent alternative)
+ (list 'if predicate consequent alternative))
+
+(define (begin? exp) (tagged-list? exp 'begin))
+
+(define (begin-actions exp) (cdr exp))
+
+(define (last-exp? seq) (null? (cdr seq)))
+
+(define (first-exp seq) (car seq))
+
+(define (rest-exps seq) (cdr seq))
+
+(define (sequence->exp seq)
+ (cond
+ ((null? seq) seq)
+ ((last-exp? seq) (first-exp seq))
+ (else (make-begin seq))))
+
+(define (make-begin seq) (cons 'begin seq))
+
+(define (application? exp) (pair? exp))
+
+(define (operator exp) (car exp))
+
+(define (operands exp) (cdr exp))
+
+(define (no-operands? ops) (null? ops))
+
+(define (first-operand ops) (car ops))
+
+(define (rest-operands ops) (cdr ops))
+
+(define (cond? exp) (tagged-list? exp 'cond))
+
+(define (cond-clauses exp) (cdr exp))
+
+(#%provide cond-predicate)
+(define (cond-predicate clause)
+ (car clause))
+
+(define (cond-else-clause? clause)
+ (eq? (cond-predicate clause) 'else))
+
+(define (cond-actions clause) (cdr clause))
+
+(define (cond->if exp)
+ (expand-clauses (cond-clauses exp)))
+
+(define (expand-clauses clauses)
+ (if (null? clauses)
+ 'false
+ (let
+ ((first (car clauses))
+ (rest (cdr clauses)))
+ (if (cond-else-clause? first)
+ (if (null? rest)
+ (sequence->exp (cond-actions first))
+ (error
+ "ELSE clause isn't last -- COND->IF"
+ clauses))
+ (make-if
+ (cond-predicate first)
+ (if (cond-extended? first)
+ (list (cond-recipient first) (cond-predicate first))
+ (sequence->exp (cond-actions first)))
+ (expand-clauses rest))))))
+
+(#%provide cond-recipient)
+(define (cond-recipient clause) (caddr clause))
+
+(#%provide cond-extended?)
+(define (cond-extended? clause)
+ (tagged-list? (cdr clause) '=>))
+
+(#%provide let?)
+(define (let? exp) (tagged-list? exp 'let))
+
+(#%provide binding-var)
+(define (binding-var binding)
+ (car binding))
+
+(#%provide binding-exp)
+(define (binding-exp binding)
+ (cadr binding))
+
+(#%provide let-bindings)
+(define (let-bindings exp) (cadr exp))
+
+(#%provide let-body)
+(define (let-body exp) (cddr exp))
+
+(#%provide let->combination)
+(define (let->combination exp)
+ (if (null? (let-bindings exp))
+ (if (null? (cdr (let-body exp)))
+ (car (let-body exp))
+ (cons 'begin (let-body exp)))
+ (list
+ (cons 'lambda
+ (cons
+ (map binding-var (let-bindings exp))
+ (let-body exp)))
+ (map binding-exp (let-bindings exp)))))
+
+(#%provide make-let)
+(define (make-let bindings body)
+ (cons 'let (cons bindings body)))
+
+(define (true? x)
+ (not (eq? x false)))
+
+(define (false? x)
+ (eq? x false))
+
+(define (make-procedure parameters body env)
+ (list 'procedure parameters body env))
+
+(define (compound-procedure? p)
+ (tagged-list? p 'procedure))
+
+(#%provide procedure-parameters)
+(define (procedure-parameters p) (cadr p))
+
+(#%provide procedure-body)
+(define (procedure-body p) (caddr p))
+
+(#%provide procedure-environment)
+(define (procedure-environment p) (cadddr p))
+
+(#%provide enclosing-environment)
+(define (enclosing-environment env) (cdr env))
+
+(#%provide first-frame)
+(define (first-frame env) (car env))
+
+(#%provide the-empty-environment)
+(define the-empty-environment '())
+
+(#%provide make-frame)
+(define (make-frame variables values)
+ (cons variables values))
+
+(#%provide frame-variables)
+(define (frame-variables frame) (car frame))
+
+(#%provide frame-values)
+(define (frame-values frame) (cdr frame))
+
+(#%provide add-binding-to-frame!)
+(define (add-binding-to-frame! var val frame)
+ (set-car! frame (cons var (car frame)))
+ (set-cdr! frame (cons val (cdr frame))))
+
+(#%provide extend-environment)
+(define (extend-environment vars vals base-env)
+ (if (= (length vars) (length vals))
+ (cons (make-frame vars vals) base-env)
+ (if (< (length vars) (length vals))
+ (error "Too many arguments supplied" vars vals)
+ (error "Too few arguments supplied" vars vals))))
+
+(#%provide lookup-variable-value)
+(define (lookup-variable-value var env)
+ (define (env-loop env)
+ (define (scan vars vals)
+ (cond
+ ((null? vars)
+ (env-loop (enclosing-environment env)))
+ ((eq? var (car vars))
+ (car vals))
+ (else (scan (cdr vars) (cdr vals)))))
+ (if (eq? env the-empty-environment)
+ (error "Unbound variable" var)
+ (let ((frame (first-frame env)))
+ (scan
+ (frame-variables frame)
+ (frame-values frame)))))
+ (env-loop env))
+
+(#%provide set-variable-value!)
+(define (set-variable-value! var val env)
+ (define (env-loop env)
+ (define (scan vars vals)
+ (cond
+ ((null? vars)
+ (env-loop (enclosing-environment env)))
+ ((eq? var (car vars))
+ (set-car! vals val))
+ (else (scan (cdr vars) (cdr vals)))))
+ (if (eq? env the-empty-environment)
+ (error "Unbound variable" var)
+ (let ((frame (first-frame env)))
+ (scan
+ (frame-variables frame)
+ (frame-values frame)))))
+ (env-loop env))
+
+(#%provide define-variable!)
+(define (define-variable! var val env)
+ (let ((frame (first-frame env)))
+ (define (scan vars vals)
+ (cond
+ ((null? vars)
+ (add-binding-to-frame! var val frame))
+ ((eq? var (car vars))
+ (set-car! vals val))
+ (else (scan (cdr vars) (cdr vals)))))
+ (scan
+ (frame-variables frame)
+ (frame-values frame))))
+
+(define (setup-environment)
+ (let
+ ((initial-env
+ (extend-environment
+ (primitive-procedure-names)
+ (primitive-procedure-objects)
+ the-empty-environment)))
+ (define-variable! 'true true initial-env)
+ (define-variable! 'false false initial-env)
+ initial-env))
+
+(define (primitive-procedure? proc)
+ (tagged-list? proc 'primitive))
+
+(define (primitive-implementation proc) (cadr proc))
+
+(define primitive-procedures
+ (list
+ #| (list 'car car) |#
+ #| (list 'cdr cdr) |#
+ #| (list 'cons cons) |#
+ #| (list 'list list) |#
+ (list 'null? null?)
+ (list '+ +)
+ (list '- -)
+ (list '* *)
+ (list '/ /)
+ (list '> >)
+ (list '< <)
+ (list '= =)
+ (list '<= <=)
+ (list '>= >=)
+ (list 'newline newline)
+ (list 'display display)))
+
+(define (primitive-procedure-names)
+ (map car primitive-procedures))
+
+(define (primitive-procedure-objects)
+ (map
+ (lambda (proc) (list 'primitive (cadr proc)))
+ primitive-procedures))
+
+(define (apply-primitive-procedure proc args)
+ (apply
+ (primitive-implementation proc) args))
+
+(define input-prompt ";;; L-Eval input:")
+(define output-prompt ";;; L-Eval value:")
+
+(#%provide driver-loop)
+(define (driver-loop)
+ (prompt-for-input input-prompt)
+ (let ((input (read)))
+ (let ((output (actual-value input the-global-environment)))
+ (announce-output output-prompt)
+ (user-print output)))
+ (driver-loop))
+
+(define (prompt-for-input string)
+ (newline)
+ (newline)
+ (display string)
+ (newline))
+
+(define (announce-output string)
+ (newline)
+ (display string)
+ (newline))
+
+(define (user-print object)
+ (if (compound-procedure? object)
+ (display
+ (list
+ 'compound-procedure
+ (procedure-parameters object)
+ (procedure-body object)
+ '<procedure-env>))
+ (display object)))
+
+(#%provide the-global-environment)
+(define the-global-environment (setup-environment))
+(define (unless-bad condition usual-value exceptional-value)
+ (if condition exceptional-value usual-value))
+
+#| 4.25 |#
+
+(#%provide factorial-bad)
+(define (factorial-bad n)
+ (unless-bad (= n 1)
+ (* n (factorial-bad (- n 1)))
+ 1))
+
+#| 4.26 |#
+
+(define (unless? exp) (tagged-list? exp 'unless))
+
+(define (unless-predicate exp) (cadr exp))
+
+(define (unless-usual exp) (caddr exp))
+
+(define (unless-exceptional exp) (cadddr exp))
+
+(#%provide unless->if)
+(define (unless->if exp)
+ (make-if
+ (unless-predicate exp)
+ (unless-exceptional exp)
+ (unless-usual exp)))
+
+;; An Interpreter with Lazy Evaluation
+
+(#%provide actual-value)
+(define (actual-value exp env)
+ (force-it (eval exp env)))
+
+(define (list-of-arg-values exps env)
+ (if (no-operands? exps)
+ '()
+ (cons
+ (actual-value (first-operand exps) env)
+ (list-of-arg-values (rest-operands exps) env))))
+
+(define (list-of-delayed-args exps env)
+ (if (no-operands? exps)
+ '()
+ (cons
+ (delay-it (first-operand exps) env)
+ (list-of-delayed-args
+ (rest-operands exps)
+ env))))
+
+(define (force-it obj)
+ #| (if (thunk? obj) |#
+ #| (actual-value |#
+ #| (thunk-exp obj) |#
+ #| (thunk-env obj)) |#
+ #| obj)) |#
+ (cond
+ ((thunk? obj)
+ (let
+ ((result
+ (actual-value
+ (thunk-exp obj)
+ (thunk-env obj))))
+ (set-car! obj 'evaluated-thunk)
+ (set-car! (cdr obj) result)
+ (set-cdr! (cdr obj) '())
+ result))
+ ((evaluated-thunk? obj)
+ (thunk-value obj))
+ (else obj)))
+
+(define (delay-it exp env)
+ (list 'thunk exp env))
+
+(define (thunk? obj)
+ (tagged-list? obj 'thunk))
+
+(define (thunk-exp thunk) (cadr thunk))
+
+(define (thunk-env thunk) (caddr thunk))
+
+(define (evaluated-thunk? obj)
+ (tagged-list? obj 'evaluated-thunk))
+
+(define (thunk-value evaluated-thunk)
+ (cadr evaluated-thunk))
+
+#| 4.27 |#
+
+#| (define count 0) |#
+
+#| (define (id x) |#
+#| (set! count (+ count 1)) |#
+#| x) |#
+
+#| (define w (id (id 10))) |#
+
+#| count |#
+;; 1
+
+#| w |#
+;; 10
+
+#| count |#
+;; 2
+
+#| 4.28 |#
+
+(define (max a b)
+ (if (< a b) b a))
+
+(define (plus-or-max x a b)
+ (if (= x 0) + max) a b)
+
+#| 4.29 |#
+
+(#%provide repetitive)
+(define repetitive
+ '(define (list-of-30 val)
+ (define (loop n)
+ (if (= n 0)
+ '()
+ (cons val (loop (- n 1)))))
+ (loop 30)))
+
+(#%provide expensive)
+(define expensive
+ '(define (fib-slow n)
+ (cond
+ ((= n 0) 0)
+ ((= n 1) 1)
+ (else
+ (+
+ (fib-slow (- n 2))
+ (fib-slow (- n 1)))))))
+
+(#%provide memo-test)
+(define memo-test '(list-of-30 (fib-slow 30)))
+
+;; with memo:
+
+#| (define count 0) |#
+
+#| (define (id x) |#
+#| (set! count (+ count 1)) |#
+#| x) |#
+
+#| (define (square x) (* x x)) |#
+
+#| (square (id 10)) |#
+;; 100
+
+#| count |#
+;; 1
+
+;; without memo:
+
+#| (define count 0) |#
+
+#| (define (id x) |#
+#| (set! count (+ count 1)) |#
+#| x) |#
+
+#| (define (square x) (* x x)) |#
+
+#| (square (id 10)) |#
+;; 100
+
+#| count |#
+;; 2
+
+#| 4.30 |#
+
+(#%provide for-each-def)
+(define for-each-def
+ '(define (for-each proc items)
+ (if (null? items)
+ 'done
+ (begin
+ (proc (car items))
+ (for-each proc (cdr items))))))
+
+(#%provide for-each-example)
+(define for-each-example
+ '(for-each
+ (lambda (x)
+ (display x)
+ (newline))
+ (list 57 321 88)))
+
+;; this works because the side-effecting procedures
+;; are in operator position
+
+(#%provide p1-def)
+(define p1-def
+ '(define (p1 x)
+ (set! x (cons x '(2)))
+ x))
+
+(#%provide p2-def)
+(define p2-def
+ '(define (p2 x)
+ (define (p e)
+ e
+ x)
+ (p (set! x (cons x '(2))))))
+
+;; (p1 1)
+;; (1 2)
+
+;; (p2 1)
+;; 1
+
+;; Streams as Lazy Lists
+
+(#%provide list-defs)
+(define list-defs
+ '(begin
+ (define (cons x y) (lambda (m) (m x y)))
+ (define (car z) (z (lambda (p q) p)))
+ (define (cdr z) (z (lambda (p q) q)))
+ (define (list-ref items n)
+ (if (= n 0)
+ (car items)
+ (list-ref (cdr items) (- n 1))))
+ (define (map proc items)
+ (if (null? items)
+ '()
+ (cons (proc (car items)) (map proc (cdr items)))))
+ (define (scale-list items factor)
+ (map (lambda (x) (* x factor)) items))
+ (define (add-lists list1 list2)
+ (cond
+ ((null? list1) list2)
+ ((null? list2) list1)
+ (else
+ (cons
+ (+ (car list1) (car list2))
+ (add-lists (cdr list1) (cdr list2))))))
+ (define ones (cons 1 ones))
+ (define integers (cons 1 (add-lists ones integers)))
+ (define (integral integrand initial-value dt)
+ (define int
+ (cons
+ initial-value
+ (add-lists (scale-list integrand dt) int)))
+ int)))
+
+#| 4.33 |#
+
+(#%provide list-test)
+(define list-test '(car '(a b c)))
+
+(define (list-rep exp env)
+ (if (pair? exp)
+ (make-procedure
+ '(m)
+ '((m x y))
+ (extend-environment
+ '(x y)
+ (list
+ (list-rep (car exp) env)
+ (list-rep (cdr exp) env))
+ env))
+ exp))