allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (09/24/89)
Posting-number: Volume 8, Issue 56 Submitted-by: net@tub.UUCP (Oliver Laumann) Archive-name: elk/part08 [Let this be a lesson to submitters: this was submitted as uuencoded, compressed files. I lost the source information while unpacking it; this is the best approximation I could come up with. ++bsa] #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of archive 8 (of 14)." # Contents: scm/xlib.core scm/oops tst/cc tst/dynamic-wind tst/fact # tst/fact2 tst/fib tst/compile tst/hanoi tst/port tst/prim tst/rat+ # tst/runge-kutta tst/sqrt tst/unify tst/mondo tst/fix tst/ramanujan # tst/Y tst/cell tst/co lib lib/xlib lib/xlib/examples # lib/xlib/examples/lines lib/xlib/examples/hello # lib/xlib/examples/poly # Wrapped by net@tub on Sun Sep 17 17:32:30 1989 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f scm/xlib.core -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"scm/xlib.core\" else echo shar: Extracting \"scm/xlib.core\" \(8136 characters\) sed "s/^X//" >scm/xlib.core <<'END_OF_scm/xlib.core' X;;; -*-Scheme-*- X;;; X;;; X11 interface X X(require 'xlib.o) X X;;; High level create window function with keyword arguments X X(define-macro (make-window . attr) X (let ((swa (make-vector (1+ (length set-window-attributes-slots)) ())) X (parent #f) (x 0) (y 0) (width #f) (height #f) (border 2)) X (vector-set! swa 0 'set-window-attributes) X (do ((a attr (cdr a))) ((null? a)) X (cond X ((not (and (pair? (car a)) (= (length (car a)) 2))) X (error 'make-window "bad argument ~s" (car a))) X ((memq (caar a) '(parent x y width height border)) X (eval `(set! ,(caar a) (cadar a)))) X (else X (let ((k (assq (caar a) set-window-attributes-slots))) X (if k X (eval `(vector-set! swa ,(cdr k) ,(cadar a))) X (error 'make-window "unknown attribute: ~s" (car a))))))) X (if (not (and width height)) X (error 'make-window "you must specify both width and height")) X (if (not parent) X (error 'make-window "you must specify a parent window")) X `(create-window ,parent ,x ,y ,width ,height ,border ,swa))) X X X;;; High level create gcontext with keyword arguments X X(define-macro (make-gcontext . attr) X (let ((gcv (make-vector (1+ (length gcontext-slots)) ())) X (win #f)) X (vector-set! gcv 0 'gcontext) X (do ((a attr (cdr a))) ((null? a)) X (cond X ((not (and (pair? (car a)) (= (length (car a)) 2))) X (error 'make-gcontext "bad argument ~s" (car a))) X ((eq? (caar a) 'window) X (set! win (cadar a))) X (else X (let ((k (assq (caar a) gcontext-slots))) X (if k X (eval `(vector-set! gcv ,(cdr k) ,(cadar a))) X (error 'make-gcontext "unknown attribute: ~s" (car a))))))) X (if (not win) X (error 'make-gcontext "you must specify a window")) X `(create-gcontext ,win ,gcv))) X X X;;; Definition of the access and update functions for window attributes, X;;; geometry, gcontexts, etc. X X(define-macro (define-functions definer type fun pref) X (let ((slots (string->symbol (format #f "~s-slots" type)))) X `(for-each eval (map (lambda (s) X (,definer ',type (1+ (length ,slots)) ,fun s ,pref)) ,slots)))) X X(define (define-accessor-with-cache type num-slots fun slot pref) X (let ((name (string->symbol (format #f pref (car slot))))) X `(define (,name object) X (general-accessor object ',type ,fun ,(cdr slot))))) X X(define (define-mutator-with-cache type num-slots fun slot pref) X (let ((name (string->symbol (format #f pref (car slot))))) X `(define (,name object val) X (general-mutator object val ',type ,num-slots ,fun ,(cdr slot))))) X X(define (define-accessor type num-slots fun slot pref) X (let ((name (string->symbol (format #f pref (car slot))))) X `(define (,name . args) X (vector-ref (apply ,fun args) ,(cdr slot))))) X X X(define-functions define-accessor-with-cache X get-window-attributes get-window-attributes "window-~s") X X(define-functions define-mutator-with-cache X set-window-attributes change-window-attributes "set-window-~s!") X X(define-functions define-mutator-with-cache X window-configuration configure-window "set-window-~s!") X X(define-functions define-accessor-with-cache X geometry get-geometry "drawable-~s") X X(define-functions define-mutator-with-cache X gcontext change-gcontext "set-gcontext-~s!") X X(define-functions define-accessor-with-cache X font-info font-info "font-~s") X X(define-functions define-accessor X char-info char-info "char-~s") X X(define (min-char-info c) (char-info c 'min)) X(define (max-char-info c) (char-info c 'max)) X X(define-functions define-accessor X char-info min-char-info "min-char-~s") X X(define-functions define-accessor X char-info max-char-info "max-char-~s") X X(define-functions define-accessor X char-info text-extents "extents-~s") X X X;;; ``cache'' is an a-list of (drawable-or-gcontext-or-font . state) pairs, X;;; where state is a vector of buffers as listed below. Each slot in X;;; a vector can be #f to indicate that the cache is empty. The cache X;;; is manipulated by the ``with'' macro. X X(define cache ()) X X(put 'set-window-attributes 'cache-slot 0) X(put 'get-window-attributes 'cache-slot 1) X(put 'window-configuration 'cache-slot 2) X(put 'geometry 'cache-slot 3) X(put 'gcontext 'cache-slot 4) X(put 'font-info 'cache-slot 5) X X X;;; List of buffers that are manipulated by mutator functions and must X;;; be flushed using the associated update function when a ``with'' is X;;; left (e.g., a set-window-attributes buffer is manipulated by X;;; set-window-FOO functions; the buffer is flushed by a call to X;;; (change-window-attributes WINDOW BUFFER)): X X(define mutable-types '(set-window-attributes window-configuration gcontext)) X X(put 'set-window-attributes 'update-function change-window-attributes) X(put 'window-configuration 'update-function configure-window) X(put 'gcontext 'update-function change-gcontext) X X X;;; Some types of buffers in the cache are invalidated when other X;;; buffers are written to. For instance, a get-window-attributes X;;; buffer for a window must be filled again when the window's X;;; set-window-attributes or window-configuration buffers have been X;;; written to. X X(put 'get-window-attributes 'invalidated-by X '(set-window-attributes window-configuration)) X(put 'geometry 'invalidated-by X '(set-window-attributes window-configuration)) X X;;; Within the scope of a ``with'', the first call to a OBJECT-FOO X;;; function causes the result of the corresponding Xlib function to X;;; be retained in the cache; subsequent calls just read from the cache. X;;; Similarly, calls to Xlib functions for set-OBJECT-FOO! functions are X;;; delayed until exit of the ``with'' body or until a OBJECT-FOO X;;; is called and the cached data for this accessor function has been X;;; invalidated by the call to the mutator function (see ``invalidated-by'' X;;; property above). X X(define-macro (with object . body) X `(if (assq ,object cache) ; if it's already in the cache, just X (begin ,@body) ; execute the body. X (dynamic-wind X (lambda () X (set! cache (cons (cons ,object (make-vector 6 #f)) cache))) X (lambda () X ,@body) X (lambda () X (for-each (lambda (x) (flush-cache (car cache) x)) mutable-types) X (set! cache (cdr cache)))))) X X;;; If a mutator function has been called on an entry in the cache X;;; of the given type, flush it by calling the right update function. X X(define (flush-cache entry type) X (let* ((slot (get type 'cache-slot)) X (buf (vector-ref (cdr entry) slot))) X (if buf X (begin X ((get type 'update-function) (car entry) buf) X (vector-set! (cdr entry) slot #f))))) X X;;; General accessor function (OBJECT-FOO). See if the data in the X;;; cache have been invalidated. If this is the case, or if the cache X;;; has not yet been filled, fill it. X X(define (general-accessor object type fun slot) X (let ((v) (entry (assq object cache))) X (if entry X (let ((cache-slot (get type 'cache-slot)) X (inval (get type 'invalidated-by))) X (if inval X (let ((must-flush #f)) X (for-each X (lambda (x) X (if (vector-ref (cdr entry) (get x 'cache-slot)) X (set! must-flush #t))) X inval) X (if must-flush X (begin X (for-each (lambda (x) (flush-cache entry x)) inval) X (vector-set! (cdr entry) cache-slot #f))))) X (if (not (vector-ref (cdr entry) cache-slot)) X (vector-set! (cdr entry) cache-slot (fun object))) X (set! v (vector-ref (cdr entry) cache-slot))) X (set! v (fun object))) X (vector-ref v slot))) X X X;;; General mutator function (set-OBJECT-FOO!). If the cache is empty, X;;; put a new buffer of the given type and size into it. Write VAL X;;; into the buffer. X X(define (general-mutator object val type num-slots fun slot) X (let ((entry (assq object cache))) X (if entry X (let ((cache-slot (get type 'cache-slot))) X (if (not (vector-ref (cdr entry) cache-slot)) X (let ((v (make-vector num-slots ()))) X (vector-set! v 0 type) X (vector-set! (cdr entry) cache-slot v) X (vector-set! v slot val)) X (vector-set! (vector-ref (cdr entry) cache-slot) slot val))) X (let ((v (make-vector num-slots ()))) X (vector-set! v 0 type) X (vector-set! v slot val) X (fun object v))))) END_OF_scm/xlib.core if test 8136 -ne `wc -c <scm/xlib.core`; then echo shar: \"scm/xlib.core\" unpacked with wrong size! fi # end of overwriting check fi if test -f scm/oops -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"scm/oops\" else echo shar: Extracting \"scm/oops\" \(8713 characters\) sed "s/^X//" >scm/oops <<'END_OF_scm/oops' X;;; -*-Scheme-*- X;;; X;;; A simple oops package X X(require 'hack 'hack.o) X X(provide 'oops) X X(define class-size 5) X(define instance-size 3) X X;;; Classes and instances are represented as vectors. The first X;;; two slots (tag and class-name) are common to classes and instances. X X(define (tag v) (vector-ref v 0)) X(define (set-tag! v t) (vector-set! v 0 t)) X X(define (class-name v) (vector-ref v 1)) X(define (set-class-name! v n) (vector-set! v 1 n)) X X(define (class-instance-vars c) (vector-ref c 2)) X(define (set-class-instance-vars! c v) (vector-set! c 2 v)) X X(define (class-env c) (vector-ref c 3)) X(define (set-class-env! c e) (vector-set! c 3 e)) X X(define (class-super c) (vector-ref c 4)) X(define (set-class-super! c s) (vector-set! c 4 s)) X X(define (instance-env i) (vector-ref i 2)) X(define (set-instance-env! i e) (vector-set! i 2 e)) X X;;; Methods are bound in the class environment. X X(define (method-known? method class) X (eval `(bound? ',method) (class-env class))) X X(define (lookup-method method class) X (eval method (class-env class))) X X(define (class? c) X (and (vector? c) (= (vector-length c) class-size) (eq? (tag c) 'class))) X X(define (check-class sym c) X (if (not (class? c)) X (error sym "argument is not a class"))) X X(define (instance? i) X (and (vector? i) (= (vector-length i) instance-size) X (eq? (tag i) 'instance))) X X(define (check-instance sym i) X (if (not (instance? i)) X (error sym "argument is not an instance"))) X X;;; Evaluate `body' within the scope of instance `i'. X X(define-macro (with-instance i . body) X `(eval '(begin ,@body) (instance-env ,i))) X X;;; Set a variable in an instance. X X(define (instance-set! instance var val) X (eval `(set! ,var ',val) (instance-env instance))) X X;;; Set a class variable when no instance is available. X X(define (class-set! class var val) X (eval `(set! ,var ',val) (class-env class))) X X;;; Convert a class variable spec into a binding suitable for a `let'. X X(define (make-binding var) X (if (symbol? var) X (list var ()) ; No initializer given; use () X var)) ; Initializer has been specified; leave alone X X;;; Check whether the elements of `vars' are either a symbol or X;;; of the form (symbol initializer). X X(define (check-vars vars) X (if (not (null? vars)) X (if (not (or (symbol? (car vars)) X (and (pair? (car vars)) (= (length (car vars)) 2) X (symbol? (caar vars))))) X (error 'define-class "bad variable spec: ~s" (car vars)) X (check-vars (cdr vars))))) X X;;; Check whether the class var spec `v' is already a member of X;;; the list `l'. If this is the case, check whether the initializers X;;; are identical. X X(define (find-matching-var l v) X (cond X ((null? l) #f) X ((eq? (caar l) (car v)) X (if (not (equal? (cdar l) (cdr v))) X (error 'define-class "initializer mismatch: ~s and ~s" X (car l) v) X #t)) X (else (find-matching-var (cdr l) v)))) X X;;; Same as above, but don't check initializer. X X(define (find-var l v) X (cond X ((null? l) #f) X ((eq? (caar l) (car v)) #t) X (else (find-var (cdr l) v)))) X X;;; Create a new list of class var specs by discarding all variables X;;; from `b' that are already a member of `a' (with identical initializers). X X(define (join-vars a b) X (cond X ((null? b) a) X ((find-matching-var a (car b)) (join-vars a (cdr b))) X (else (join-vars (cons (car b) a) (cdr b))))) X X;;; The syntax is as follows: X;;; (define-class class-name . options) X;;; options are: (super-class class-name) X;;; (class-vars . var-specs) X;;; (instance-vars . var-specs) X;;; each var-spec is either a symbol or (symbol initializer). X X(define-macro (define-class name . args) X (let ((class-vars) (instance-vars (list (make-binding 'self))) X (super) (super-class-env)) X (do ((a args (cdr a))) ((null? a)) X (cond X ((not (pair? (car a))) X (error 'define-class "bad argument: ~s" (car a))) X ((eq? (caar a) 'class-vars) X (check-vars (cdar a)) X (set! class-vars (cdar a))) X ((eq? (caar a) 'instance-vars) X (check-vars (cdar a)) X (set! instance-vars (append instance-vars X (map make-binding (cdar a))))) X ((eq? (caar a) 'super-class) X (if (> (length (cdar a)) 1) X (error 'define-class "only one super-class allowed")) X (set! super (cadar a))) X (else X (error 'define-class "bad keyword: ~s" (caar a))))) X (if super X (let ((class (eval super))) X (set! super-class-env (class-env class)) X (set! instance-vars (join-vars (class-instance-vars class) X instance-vars))) X (set! super-class-env (the-environment))) X `(define ,name X (let ((c (make-vector class-size ()))) X (set-tag! c 'class) X (set-class-name! c ',name) X (set-class-instance-vars! c ',instance-vars) X (set-class-env! c (eval `(let* ,(map make-binding ',class-vars) X (the-environment)) X ,super-class-env)) X (set-class-super! c ',super) X c)))) X X(define-macro (define-method class lambda-list . body) X (if (not (pair? lambda-list)) X (error 'define-method "bad lambda list")) X `(begin X (check-class 'define-method ,class) X (let ((env (class-env ,class)) X (method (car ',lambda-list)) X (args (cdr ',lambda-list)) X (forms ',body)) X (eval `(define ,method (lambda ,args ,@forms)) env) X #v))) X X;;; All arguments of the form (instance-var init-value) are used X;;; to initialize the specified instance variable; then an X;;; initialize-instance message is sent with all remaining X;;; arguments. X X(define-macro (make-instance class . args) X `(begin X (check-class 'make-instance ,class) X (let* ((e (the-environment)) X (i (make-vector instance-size #f)) X (class-env (class-env ,class)) X (instance-vars (class-instance-vars ,class))) X (set-tag! i 'instance) X (set-class-name! i ',class) X (set-instance-env! i (eval `(let* ,instance-vars (the-environment)) X class-env)) X (eval `(set! self ,i) (instance-env i)) X (init-instance ',args ,class i e) X i))) X X(define (init-instance args class instance env) X (let ((other-args)) X (do ((a args (cdr a))) ((null? a)) X (if (and (pair? (car a)) (= (length (car a)) 2) X (find-var (class-instance-vars class) (car a))) X (instance-set! instance (caar a) (eval (cadar a) env)) X (set! other-args (cons (eval (car a) env) other-args)))) X (call-init-methods class instance (reverse! other-args)))) X X;;; Call all initialize-instance methods in super-class to sub-class X;;; order in the environment of `instance' with arguments `args'. X X(define (call-init-methods class instance args) X (let ((called ())) X (let loop ((class class)) X (if (class-super class) X (loop (eval (class-super class)))) X (if (method-known? 'initialize-instance class) X (let ((method (lookup-method 'initialize-instance class))) X (if (not (memq method called)) X (begin X (apply (hack-procedure-environment! X method (instance-env instance)) X args) X (set! called (cons method called))))))))) X X(define (send instance msg . args) X (check-instance 'send instance) X (let ((class (eval (class-name instance)))) X (if (not (method-known? msg class)) X (error 'send "message not understood: ~s" `(,msg ,@args)) X (apply (hack-procedure-environment! (lookup-method msg class) X (instance-env instance)) X args)))) X X;;; If the message is not understood, return #f. Otherwise return X;;; a list of one element, the result of the method. X X(define (send-if-handles instance msg . args) X (check-instance 'send-if-handles instance) X (let ((class (eval (class-name instance)))) X (if (not (method-known? msg class)) X #f X (list (apply (hack-procedure-environment! (lookup-method msg class) X (instance-env instance)) X args))))) X X(define (describe-class c) X (check-class 'describe-class c) X (format #t "Class name: ~s~%" (class-name c)) X (format #t "Superclass: ~s~%" X (if (class-super c) X (class-super c) X 'None)) X (format #t "Instancevars: ") X (do ((v (class-instance-vars c) (cdr v)) (space #f #t)) ((null? v)) X (if space X (format #t " ")) X (print (cons (caar v) (cadar v)))) X (format #t "Classvars/Methods: ") X (define v (car (environment->list (class-env c)))) X (if v X (do ((f v (cdr f)) (space #f #t)) ((null? f)) X (if space X (format #t " ")) X (print (car f))) X (print 'None)) X #v) X X(define (describe-instance i) X (check-instance 'describe-instance i) X (format #t "Instance of: ~s~%" (class-name i)) X (format #t "Instancevars: ") X (do ((f (car (environment->list (instance-env i))) (cdr f)) X (space #f #t)) ((null? f)) X (if space X (format #t " ")) X (print (car f))) X #v) END_OF_scm/oops if test 8713 -ne `wc -c <scm/oops`; then echo shar: \"scm/oops\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/cc -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/cc\" else echo shar: Extracting \"tst/cc\" \(474 characters\) sed "s/^X//" >tst/cc <<'END_OF_tst/cc' X;;; -*-Scheme-*- X X(define acc) X(define bcc) X(define n 5) X X(define (a) X (if (not (= 0 (call-with-current-continuation X (lambda (cc) X (set! acc cc) 0)))) X (if (> n 0) X (begin X (set! n (- n 1)) X (display "resume b") (newline) X (bcc 1)) X #v) X acc)) X X(define (b) X (if (not (= 0 (call-with-current-continuation X (lambda (cc) X (set! bcc cc) 0)))) X (begin X (display "resume a") (newline) X (acc 1))) X bcc) X X(a) X(b) X(acc 1) END_OF_tst/cc if test 474 -ne `wc -c <tst/cc`; then echo shar: \"tst/cc\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/dynamic-wind -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/dynamic-wind\" else echo shar: Extracting \"tst/dynamic-wind\" \(641 characters\) sed "s/^X//" >tst/dynamic-wind <<'END_OF_tst/dynamic-wind' X;;; -*-Scheme-*- X X(define point) X(define saved #f) X(define (print s) (display s) (newline)) X X(define (inner) X (dynamic-wind X (lambda () (print " in")) X (lambda () (dynamic-wind X (lambda () (print " in")) X (lambda () (if saved X (begin (print " throw") (point 100)) X (begin X (call-with-current-continuation X (lambda (x) (set! point x))) X (print " catch") X (set! saved #t) #v))) X (lambda () (print " out")))) X (lambda () (print " out")))) X X(define (outer) X (dynamic-wind X (lambda () (print 'in)) X (lambda () (inner)) X (lambda () (print 'out)))) X X(outer) X(outer) END_OF_tst/dynamic-wind if test 641 -ne `wc -c <tst/dynamic-wind`; then echo shar: \"tst/dynamic-wind\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/fact -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/fact\" else echo shar: Extracting \"tst/fact\" \(197 characters\) sed "s/^X//" >tst/fact <<'END_OF_tst/fact' X;;; -*-Scheme-*- X X(define (factorial n) X (define (iter product counter) X (if (> counter n) X product X (iter (* counter product) X (+ counter 1)))) X (iter 1 1)) X X(print (factorial 10)) END_OF_tst/fact if test 197 -ne `wc -c <tst/fact`; then echo shar: \"tst/fact\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/fact2 -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/fact2\" else echo shar: Extracting \"tst/fact2\" \(122 characters\) sed "s/^X//" >tst/fact2 <<'END_OF_tst/fact2' X;;; -*-Scheme-*- X X(define (f n) X (let fact ((i n) (a 1)) X (if (zero? i) X a X (fact (- i 1) (* a i))))) X X(print (f 10)) END_OF_tst/fact2 if test 122 -ne `wc -c <tst/fact2`; then echo shar: \"tst/fact2\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/fib -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/fib\" else echo shar: Extracting \"tst/fib\" \(290 characters\) sed "s/^X//" >tst/fib <<'END_OF_tst/fib' X;;; -*-Scheme-*- X X(define (f n) X (if (= n 0) X 0 X (let fib ((i n) (a1 1) (a2 0)) X (if (= i 1) X a1 X (fib (- i 1) (+ a1 a2) a1))))) X X(print (f 20)) X X(define tau (/ (+ 1 (sqrt 5.0)) 2)) X X(define (fib n) X (/ (+ (expt tau n) (expt tau (- 0 n))) (sqrt 5.0))) X X(print (fib 20)) END_OF_tst/fib if test 290 -ne `wc -c <tst/fib`; then echo shar: \"tst/fib\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/compile -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/compile\" else echo shar: Extracting \"tst/compile\" \(10445 characters\) sed "s/^X//" >tst/compile <<'END_OF_tst/compile' X(require 'cscheme) X X; X; Optimizing scheme compiler X; supports quote, set!, if, lambda special forms, X; constant refs, variable refs and proc applications X; X; Using Clusures for Code Generation X; Marc Feeley and Guy LaPalme X; Computer Language, Vol. 12, No. 1, pp. 47-66 X; 1987 X; X X(define (compile expr) X ((gen expr nil ()))) X X(define (gen expr env term) X (cond X ((symbol? expr) X (ref (variable expr env) term)) X ((not (pair? expr)) X (cst expr term)) X ((eq? (car expr) 'quote) X (cst (cadr expr) term)) X ((eq? (car expr) 'set!) X (set (variable (cadr expr) env) (gen (caddr expr) env ()) term)) X ((eq? (car expr) 'if) X (gen-tst (gen (cadr expr) env ()) X (gen (caddr expr) env term) X (gen (cadddr expr) env term))) X ((eq? (car expr) 'lambda) X (let ((p (cadr expr))) X (prc p (gen (caddr expr) (allocate p env) #t) term))) X (else X (let ((args (map (lambda (x) (gen x env ())) (cdr expr)))) X (let ((var (and (symbol? (car expr)) (variable (car expr) env)))) X (if (global? var) X (app (cons var args) #t term) X (app (cons (gen (car expr) env ()) args) () term))))))) X X X(define (allocate parms env) X (cond ((null? parms) env) X ((symbol? parms) (cons parms env)) X (else X (cons (car parms) (allocate (cdr parms) env))))) X X(define (variable symb env) X (let ((x (memq symb env))) X (if x X (- (length env) (length x)) X (begin X (if (not (assq symb -glo-env-)) (define-global symb '-undefined-)) X (assq symb -glo-env-))))) X X(define (global? var) X (pair? var)) X X(define (cst val term) X (cond ((eqv? val 1) X ((if term gen-1* gen-1))) X ((eqv? val 2) X ((if term gen-2* gen-2))) X ((eqv? val nil) X ((if term gen-null* gen-null))) X (else X ((if term gen-cst* gen-cst) val)))) X X(define (ref var term) X (cond ((global? var) X ((if term gen-ref-glo* gen-ref-glo) var)) X ((= var 0) X ((if term gen-ref-loc-1* gen-ref-loc-1))) X ((= var 1) X ((if term gen-ref-loc-2* gen-ref-loc-2))) X ((= var 2) X ((if term gen-ref-loc-3* gen-ref-loc-3))) X (else X ((if term gen-ref* gen-ref) var)))) X X(define (set var val term) X (cond ((global? var) X ((if term gen-set-glo* gen-set-glo) var val)) X ((= var 0) X ((if term gen-set-loc-1* gen-set-loc-1) val)) X ((= var 1) X ((if term gen-set-loc-2* gen-set-loc-2) val)) X ((= var 2) X ((if term gen-set-loc-3* gen-set-loc-3) val)) X (else X ((if term gen-set* gen-set) var val)))) X X(define (prc parms body term) X ((cond ((null? parms) X (if term gen-pr0* gen-pr0)) X ((symbol? parms) X (if term gen-pr1/rest* gen-pr1/rest)) X ((null? (cdr parms)) X (if term gen-pr1* gen-pr1)) X ((symbol? (cdr parms)) X (if term gen-pr2/rest* gen-pr2/rest)) X ((null? (cddr parms)) X (if term gen-pr2* gen-pr2)) X ((symbol? (cddr parms)) X (if term gen-pr3/rest* gen-pr3/rest)) X ((null? (cdddr parms)) X (if term gen-pr3 gen-pr3)) X (else X (error "too many parameters in a lambda-expression"))) X body)) X X(define (app vals glo term) X (apply (case (length vals) X ((1) (if glo X (if term gen-ap0-glo* gen-ap0-glo) X (if term gen-ap0* gen-ap0))) X ((2) (if glo X (if term gen-ap1-glo* gen-ap1-glo) X (if term gen-ap1* gen-ap1))) X ((3) (if glo X (if term gen-ap2-glo* gen-ap2-glo) X (if term gen-ap2* gen-ap2))) X ((4) (if glo X (if term gen-ap3-glo* gen-ap3-glo) X (if term gen-ap3* gen-ap3))) X (else (error "too many arguments in a proc application"))) X vals)) X; X; code generation for non-terminal evaluations X; X X; X; constants X; X X(define (gen-1) (lambda () 1)) X(define (gen-2) (lambda () 2)) X(define (gen-null) (lambda () ())) X(define (gen-cst a) (lambda () a)) X X; X; variable reference X; X X(define (gen-ref-glo a) (lambda () (cdr a))) ; global var X(define (gen-ref-loc-1) (lambda () (cadr *env*))) ; first local var X(define (gen-ref-loc-2) (lambda () (caddr *env*))) ; second local var X(define (gen-ref-loc-3) (lambda () (cadddr *env*))) ; third local var X(define (gen-ref a) (lambda () (do ((i 0 (1+ i)) ; any non-global X (env (cdr *env*) (cdr env))) X ((= i a) (car env))))) X X; X; assignment X; X X(define (gen-set-glo a b) (lambda () (set-cdr! a (b)))) X(define (gen-set-loc-1 a) (lambda () (set-car! (cdr *env*) (a)))) X(define (gen-set-loc-2 a) (lambda () (set-car! (cddr *env*) (a)))) X(define (gen-set-loc-3 a) (lambda () (set-car! (cdddr *env*) (a)))) X(define (gen-set a b) (lambda () (do ((i 0 (1+ i)) X (env (cdr *env*) (cdr env))) X ((= i a) (set-car! env (b)))))) X X; X; conditional X; X X(define (gen-tst a b c) (lambda () (if (a) (b) (c)))) X X; X; procedure application X; X X(define (gen-ap0-glo a) (lambda () ((cdr a)))) X(define (gen-ap1-glo a b) (lambda () ((cdr a) (b)))) X(define (gen-ap2-glo a b c) (lambda () ((cdr a) (b) (c)))) X(define (gen-ap3-glo a b c d) (lambda () ((cdr a) (b) (c) (d)))) X X(define (gen-ap0 a) (lambda () ((a)))) X(define (gen-ap1 a b) (lambda () ((a) (b)))) X(define (gen-ap2 a b c) (lambda () ((a) (b) (c)))) X(define (gen-ap3 a b c d) (lambda () ((a) (b) (c) (d)))) X X; X; lambda expressions X; X X(define (gen-pr0 a) ; without "rest" parameter X (lambda () X (let ((def (cdr *env*))) X (lambda () X (set! *env* (cons *env* def)) X (a))))) X X(define (gen-pr1 a) X (lambda () X (let ((def (cdr *env*))) X (lambda (x) X (set! *env* (cons *env* (cons x def))) X (a))))) X X(define (gen-pr2 a) X (lambda () X (let ((def (cdr *env*))) X (lambda (x y) X (set! *env* (cons *env* (cons x (cons y def)))) X (a))))) X X(define (gen-pr3 a) X (lambda () X (let ((def (cdr *env*))) X (lambda (x y z) X (set! *env* (cons *env* (cons x (cons y (cons z def))))) X (a))))) X X(define (gen-pr1/rest a) X (lambda () X (let ((def (cdr *env*))) X (lambda x X (set! *env* (cons *env* (cons x def))) X (a))))) X X(define (gen-pr2/rest a) X (lambda () X (let ((def (cdr *env*))) X (lambda (x . y) X (set! *env* (cons *env* (cons x (cons y def)))) X (a))))) X X(define (gen-pr3/rest a) X (lambda () X (let ((def (cdr *env*))) X (lambda (x y . z) X (set! *env* (cons *env* (cons x (cons y (cons z def))))) X (a))))) X X; X; code generation for terminal evaluations X; X X; X; constants X; X X(define (gen-1*) X (lambda () X (set! *env* (car *env*)) X 1)) X X(define (gen-2*) X (lambda () X (set! *env* (car *env*)) X 2)) X X(define (gen-null*) X (lambda () X (set! *env* (car *env*)) X ())) X X(define (gen-cst* a) X (lambda () X (set! *env* (car *env*)) X a)) X X; X; variable reference X; X X(define (gen-ref-glo* a) X (lambda () X (set! *env* (car *env*)) X (cdr a))) X X(define (gen-ref-loc-1*) X (lambda () X (let ((val (cadr *env*))) X (set! *env* (car *env*)) X val))) X X(define (gen-ref-loc-2*) X (lambda () X (let ((val (caddr *env*))) X (set! *env* (car *env*)) X val))) X X(define (gen-ref-loc-3*) X (lambda () X (let ((val (cadddr *env*))) X (set! *env* (car *env*)) X val))) X X(define (gen-ref* a) X (lambda () X (do ((i 0 (1+ i)) X (env (cdr *env*) (cdr env))) X ((= i a) X (set! *env* (car *env*)) X (car env))))) X X; X; assignment X; X X(define (gen-set-glo* a b) X (lambda () X (set! *env* (car *env*)) X (set-cdr! a (b)))) X X(define (gen-set-loc-1* a) X (lambda () X (set! *env* (car *env*)) X (set-car! (cdr *env*) (a)))) X X(define (gen-set-loc-2* a) X (lambda () X (set! *env* (car *env*)) X (set-car! (cddr *env*) (a)))) X X(define (gen-set-loc-3* a) X (lambda () X (set! *env* (car *env*)) X (set-car! (cdddr *env*) (a)))) X X(define (gen-set* a b) X (lambda () X (do ((i 0 (1+ i)) X (env (cdr *env*) (cdr env))) X ((= i 0) X (set! *env* (car *env*)) X (set-car! env (b)))))) X X; X; procedure application X; X X(define (gen-ap0-glo* a) X (lambda () X (set! *env* (car *env*)) X ((cdr a)))) X X(define (gen-ap1-glo* a b) X (lambda () X (let ((x (b))) X (set! *env* (car *env*)) X ((cdr a) x)))) X X(define (gen-ap2-glo* a b c) X (lambda () X (let ((x (b)) (y (c))) X (set! *env* (car *env*)) X ((cdr a) x y)))) X X(define (gen-ap3-glo* a b c d) X (lambda () X (let ((x (b)) (y (c)) (z (d))) X (set! *env* (car *env*)) X ((cdr a) x y z)))) X X(define (gen-ap0* a) X (lambda () X (let ((w (a))) X (set! *env* (car *env*)) X (w)))) X X(define (gen-ap1* a b) X (lambda () X (let ((w (a)) (x (b))) X (set! *env* (car *env*)) X (w x)))) X X(define (gen-ap2* a b c) X (lambda () X (let ((w (a)) (x (b)) (y (c))) X (set! *env* (car *env*)) X (w x y)))) X X(define (gen-ap3* a b c d) X (lambda () X (let ((w (a)) (x (b)) (y (c)) (z (d))) X (set! *env* (car *env*)) X (w x y z)))) X X; X; lambda X; X X(define (gen-pr0* a) X (lambda () X (let ((def (cdr *env*))) X (set! *env* (car *env*)) X (lambda () X (set! *env* (cons *env* def)) X (a))))) X X X(define (gen-pr1* a) X (lambda () X (let ((def (cdr *env*))) X (set! *env* (car *env*)) X (lambda (x) X (set! *env* (cons *env* (cons x def))) X (a))))) X X(define (gen-pr2* a) X (lambda () X (let ((def (cdr *env*))) X (set! *env* (car *env*)) X (lambda (x y) X (set! *env* (cons *env* (cons x (cons y def)))) X (a))))) X X(define (gen-pr3* a) X (lambda () X (let ((def (cdr *env*))) X (set! *env* (car *env*)) X (lambda (x y z) X (set! *env* (cons *env* (cons x (cons y (cons z def))))) X (a))))) X X(define (gen-pr1/rest* a) X (lambda () X (let ((def (cdr *env*))) X (set! *env* (car *env*)) X (lambda x X (set! *env* (cons *env* (cons x def))) X (a))))) X X(define (gen-pr2/rest* a) X (lambda () X (let ((def (cdr *env*))) X (set! *env* (car *env*)) X (lambda (x . y) X (set! *env* (cons *env* (cons x (cons y def)))) X (a))))) X X(define (gen-pr1/rest* a) X (lambda () X (let ((def (cdr *env*))) X (set! *env* (car *env*)) X (lambda (x y . z) X (set! *env* (cons *env* (cons x (cons y (cons z def))))) X (a))))) X X; X; global defs X; X X(define (define-global var val) X (if (assq var -glo-env-) X (set-cdr! (assq var -glo-env-) val) X (set! -glo-env- (cons (cons var val) -glo-env-)))) X X(define -glo-env- (list (cons 'define define-global))) X X(define-global 'cons cons) X(define-global 'car car) X(define-global 'cdr cdr) X(define-global 'null? null?) X(define-global 'not not) X(define-global '< <) X(define-global '-1+ -1+) X(define-global '+ +) X(define-global '- -) X X; X; current environment X; X X(define *env* '(dummy)) X X; X; environment manipulation X; X X(define (restore-env) X (set! *env* (car *env*))) X X; X; evaluator X; X X(define (evaluate expr) X ((compile (list 'lambda '() expr)))) X X X (evaluate '(define 'fib X (lambda (x) X (if (< x 2) X x X (+ (fib (- x 1)) X (fib (- x 2))))))) X X(print (evaluate '(fib 10))) END_OF_tst/compile if test 10445 -ne `wc -c <tst/compile`; then echo shar: \"tst/compile\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/hanoi -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/hanoi\" else echo shar: Extracting \"tst/hanoi\" \(399 characters\) sed "s/^X//" >tst/hanoi <<'END_OF_tst/hanoi' X;;; -*-Scheme-*- X;;; X;;; Towers of Hanoi X X(define (hanoi n) X (if (zero? n) X (display "Huh?\n") X (transfer 'A 'B 'C n))) X X(define (print-move from to) X (format #t "Move disk from ~s to ~s~%" from to)) X X(define (transfer from to via n) X (if (= n 1) X (print-move from to) X (transfer from via to (1- n)) X (print-move from to) X (transfer via to from (1- n)))) X X(hanoi 3) END_OF_tst/hanoi if test 399 -ne `wc -c <tst/hanoi`; then echo shar: \"tst/hanoi\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/port -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/port\" else echo shar: Extracting \"tst/port\" \(480 characters\) sed "s/^X//" >tst/port <<'END_OF_tst/port' X;;; -*-Scheme-*- X X(let ((s1 (make-string 63 #\a)) X (s2 (make-string 66 #\b)) X (s3 (make-string 1500 #\c)) X (f (open-output-string))) X (display s1 f) X (display s2 f) X (display s3 f) X (display (string-append (get-output-string f) ".") f) X (write (string-length (get-output-string f))) X (display " ") X (print (+ 1 63 66 1500)) X (define f (open-input-string s2)) X (write (string-length s2)) X (display " ") X (print (string-length (symbol->string (read f))))) END_OF_tst/port if test 480 -ne `wc -c <tst/port`; then echo shar: \"tst/port\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/prim -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/prim\" else echo shar: Extracting \"tst/prim\" \(229 characters\) sed "s/^X//" >tst/prim <<'END_OF_tst/prim' X;;; -*-Scheme-*- X X(define (p n) X (let f ((n n) (i 2)) X (cond X ((> i n) ()) X ((integer? (/ n i)) X (cons i (f (/ n i) i))) X (else X (f n (+ i 1)))))) X X(print (p 12)) X(print (p 3628800)) X(print (p 4194304)) END_OF_tst/prim if test 229 -ne `wc -c <tst/prim`; then echo shar: \"tst/prim\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/rat+ -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/rat+\" else echo shar: Extracting \"tst/rat+\" \(668 characters\) sed "s/^X//" >tst/rat+ <<'END_OF_tst/rat+' X;;; -*-Scheme-*- X X(define (rat? r) (and (pair? r) X (integer? (car r)) X (integer? (cdr r)) X (positive? (cdr r)))) X X(define (rat+ . args) X (if (memq #f (map rat? args)) X (display "Wrong argument type in rat+") X (let* ((denominator (abs (apply lcm (map cdr args)))) X (numerator (apply + (map (lambda (quotient) X (* (car quotient) X (/ denominator (cdr quotient)))) X args))) X (common-divisor (abs (gcd numerator denominator)))) X (cons (/ numerator common-divisor) X (/ denominator common-divisor))))) X X(print (rat+ 1 2)) X(print (rat+ '(1 . 3) '(1 . 7))) X(print (rat+ (rat+ '(1 . 2) '(1 . 4)) '(1 . 4))) END_OF_tst/rat+ if test 668 -ne `wc -c <tst/rat+`; then echo shar: \"tst/rat+\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/runge-kutta -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/runge-kutta\" else echo shar: Extracting \"tst/runge-kutta\" \(1755 characters\) sed "s/^X//" >tst/runge-kutta <<'END_OF_tst/runge-kutta' X;;; -*-Scheme-*- X X(define integrate-system X (lambda (system-derivative initial-state h) X (let ((next (runge-kutta-4 system-derivative h))) X (letrec ((states X (cons initial-state X (delay (map-streams next X states))))) X states)))) X X(define runge-kutta-4 X (lambda (f h) X (let ((*h (scale-vector h)) X (*2 (scale-vector 2)) X (*1/2 (scale-vector (/ 1 2))) X (*1/6 (scale-vector (/ 1 6)))) X (lambda (y) X (let* ((k0 (*h (f y))) X (k1 (*h (f (add-vectors y (*1/2 k0))))) X (k2 (*h (f (add-vectors y (*1/2 k1))))) X (k3 (*h (f (add-vectors y k2))))) X (add-vectors y X (*1/6 (add-vectors k0 X (*2 k1) X (*2 k2) X k3)))))))) X X(define element-wise X (lambda (f) X (lambda vectors X (generate-vector X (vector-length (car vectors)) X (lambda (i) X (apply f X (map (lambda (v) (vector-ref v i)) X vectors))))))) X X(define generate-vector X (lambda (size proc) X (let ((ans (make-vector size))) X (letrec ((loop X (lambda (i) X (cond ((= i size) ans) X (else X (vector-set! ans 1 (proc i)) X (loop (+ i 1))))))) X (loop 0))))) X X(define add-vectors (element-wise +)) X X(define scale-vector X (lambda (s) X (element-wise (lambda (x) (* x s))))) X X(define map-streams X (lambda (f s) X (cons (f (head s)) X (delay (map-streams f (tail s)))))) X X(define head car) X(define tail X (lambda (stream) (force (cdr stream)))) X X(define damped-oscillator X (lambda (R L C) X (lambda (state) X (let ((Vc (vector-ref state 0)) X (Il (vector-ref state 1))) X (vector (- 0 (+ (/ Vc (* R C)) (/ Il C))) X (/ Vc L)))))) X X(define the-states X (integrate-system X (damped-oscillator 10000 1000 0.001) X '#(1 0) X 0.01)) X X(print the-states) X; (print (tail the-states)) END_OF_tst/runge-kutta if test 1755 -ne `wc -c <tst/runge-kutta`; then echo shar: \"tst/runge-kutta\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/sqrt -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/sqrt\" else echo shar: Extracting \"tst/sqrt\" \(431 characters\) sed "s/^X//" >tst/sqrt <<'END_OF_tst/sqrt' X;;; -*-Scheme-*- X X(define (sqrt x) X (define (good-enough? guess) X (< (abs (- (square guess) x)) 0.001)) X (define (improve guess) X (average guess (/ x guess))) X (define (sqrt-iter guess) X (if (good-enough? guess) X guess X (sqrt-iter (improve guess)))) X (sqrt-iter 1)) X X(define (square x) (* x x)) X(define (average x y) (/ (+ x y) 2)) X(define (abs x) (if (negative? x) (- x) x)) X X(print (sqrt 2)) X(print (sqrt 4)) END_OF_tst/sqrt if test 431 -ne `wc -c <tst/sqrt`; then echo shar: \"tst/sqrt\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/unify -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/unify\" else echo shar: Extracting \"tst/unify\" \(1287 characters\) sed "s/^X//" >tst/unify <<'END_OF_tst/unify' X;;; -*-Scheme-*- X X(define unify) X X(letrec X ((occurs? X (lambda (u v) X (and (pair? v) X (define (f l) X (and l X (or (eq? u (car l)) X (occurs? u (car l)) X (f (cdr l))))) X (f (cdr v))))) X (sigma X (lambda (u v s) X (lambda (x) X (define (f x) X (if (symbol? x) X (if (eq? x u) v x) X (cons (car x) (map f (cdr x))))) X (f (s x))))) X (try-subst X (lambda (u v s ks kf) X (let ((u (s u))) X (if (not (symbol? u)) X (uni u v s ks kf) X (let ((v (s v))) X (cond X ((eq? u v) (ks s)) X ((occurs? u v) (kf "loop")) X (else (ks (sigma u v s))))))))) X (uni X (lambda (u v s ks kf) X (cond X ((symbol? u) (try-subst u v s ks kf)) X ((symbol? v) (try-subst v u s ks kf)) X ((and (eq? (car u) (car v)) X (= (length u) (length v))) X (define (f u v s) X (if (null? u) X (ks s) X (uni (car u) X (car v) X s X (lambda (s) (f (cdr u) (cdr v) s)) X kf))) X (f (cdr u) (cdr v) s)) X (else (kf "clash")))))) X (set! unify X (lambda (u v) X (uni u X v X (lambda (x) x) X (lambda (s) (s u)) X (lambda (msg) msg))))) X X(print (unify 'x 'y)) X(print (unify '(f x y) '(g x y))) X(print (unify '(f x (h)) '(f (h) y))) X(print (unify '(f (g x) y) '(f y x))) X(print (unify '(f (g x) y) '(f y (g x)))) END_OF_tst/unify if test 1287 -ne `wc -c <tst/unify`; then echo shar: \"tst/unify\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/mondo -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/mondo\" else echo shar: Extracting \"tst/mondo\" \(240 characters\) sed "s/^X//" >tst/mondo <<'END_OF_tst/mondo' X;;; -*-Scheme-*- X X(let ((k (call-with-current-continuation (lambda (c) c)))) X (display 1) X (call-with-current-continuation (lambda (c) (k c))) X (display 2) X (call-with-current-continuation (lambda (c) (k c))) X (display 3) X (newline)) END_OF_tst/mondo if test 240 -ne `wc -c <tst/mondo`; then echo shar: \"tst/mondo\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/fix -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/fix\" else echo shar: Extracting \"tst/fix\" \(567 characters\) sed "s/^X//" >tst/fix <<'END_OF_tst/fix' X;;; -*-Scheme-*- X;;; X;;; from BYTE Feb. 88 page 208 X X(define (fixed-point f initial-value) X (define epsilon 1.0e-10) X (define (close-enough? v1 v2) X (< (abs (- v1 v2)) epsilon)) X (define (loop value) X (let ((next-value (f value))) X (if (close-enough? value next-value) X next-value X (loop next-value)))) X (loop initial-value)) X X(define (average-damp f) X (lambda (x) X (average x (f x)))) X X(define (average x y) X (/ (+ x y) 2)) X X(define (sqrt x) X (fixed-point (average-damp (lambda (y) (/ x y))) X 1)) X X(print (sqrt 2)) X(print (sqrt 4)) X X END_OF_tst/fix if test 567 -ne `wc -c <tst/fix`; then echo shar: \"tst/fix\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/ramanujan -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/ramanujan\" else echo shar: Extracting \"tst/ramanujan\" \(451 characters\) sed "s/^X//" >tst/ramanujan <<'END_OF_tst/ramanujan' X;;; -*-Scheme-*- X X(define (1/pi) X (define (step n) X (/ (* (fact (* 4 n)) (+ 1103 (* 26390 n))) X (* (expt (fact n) 4) (expt 396 (* 4 n))))) X (* (/ (sqrt 8) 9801) X (step 0))) X X(define (fact n) X (let f ((i n) (a 1)) X (if (zero? i) X a X (f (- i 1) (* a i))))) X X(define (square x) (* x x)) X X(define (expt b n) X (cond ((= n 0) 1) X ((even? n) (square (expt b (/ n 2)))) X (else (* b (expt b (- n 1)))))) X X(print (/ 1 (1/pi))) END_OF_tst/ramanujan if test 451 -ne `wc -c <tst/ramanujan`; then echo shar: \"tst/ramanujan\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/Y -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/Y\" else echo shar: Extracting \"tst/Y\" \(5985 characters\) sed "s/^X//" >tst/Y <<'END_OF_tst/Y' X; Date: 15 Nov 88 23:03:24 GMT X; From: uoregon!markv@beaver.cs.washington.edu (Mark VandeWettering) X; Organization: University of Oregon, Computer Science, Eugene OR X; Subject: The Paradoxical Combinator -- Y (LONG) X; X; Alternatively entitled: X; "Y? Why Not?" :-) X; X; The discussion that has been going on in regards to the Y combinator as X; the basic operation in implementing recursive functions are interesting. X; The practical tests that people have made have shown that the Y X; combinator is orders of magnitude slower for implementing recursion than X; directly compiling it. X; X; This is true for Scheme. I hold that for an interesting set of X; languages, (lazy languages) that this result will not necessarily hold. X; X; The problem with Y isn't its complexity, it is the fact that it is an X; inherently lazy operation. Any implementation in Scheme is clouded by X; the fact that Scheme is an applicative order evaluator, while Y prefers X; to be evaluated in normal order. X; X; X (define Y X (lambda (g) X ((lambda (h) (g (lambda (x) ((h h) x)))) X (lambda (h) (g (lambda (x) ((h h) x))))))) X; X (define fact X (lambda (f) X (lambda (n) X (if (= n 1) X 1 X (* n (f (- n 1))))))) X; X; X; Evaluating (Y fact) 2 results in the following operations in X; Scheme: X; X; The argument is (trivially) evaluated, and returns two. X; (Y fact) must be evaluated. What is it? Y and fact each evaluate X; to closures. When applied, Y binds g to fact, and executes the X; body. X; X; The body is an application of a closure to another closure. The X; operator binds h to the operand, and executes its body which.... X; X; Evaluates (g (lambda (x) ((h h) x))). The operand is a closure, X; which gets built and then returns. g evaluates to fact. We X; substitute the closure (lambda (x) ((h h) x)) in for the function X; f in the definition of fact, giving... X; X; (lambda (n) X; (if (= n 1) X; 1 X; (* n ((lambda (x) ((h h) x)) (- n 1))))) X; X; Which we return as the value of (Y fact). When we apply this to 2, we get X; X; (* 2 ((lambda (x) ((h h) x)) 1)) X; X; We then have to evaluate X; ((lambda (x) ((h h) x)) 1) X; X; or X; ((h h) 1) X; X; But remembering that h was (lambda (h) (g (lambda (x) ((h h) x)))), X; we have X; X; (((lambda (h) (g (lambda (x) ((h h) x)))) X; (lambda (h) (g (lambda (x) ((h h) x))))) X; 1) .... X; X; So, we rebind h to be the right stuff, and evaluate the body, which is X; X; ((g (lambda (x) ((h h) x))) 1) X; X; Which by the definition of g (still == fact) is just 1. X; X; (* 2 1) = 2. X; X; ######################################################################## X; X; Summary: If you didn't follow this, performing this evaluation X; was cumbersome at best. As far as compiler or interpreter is X; concerned, the high cost of evaluating this function is related X; to two different aspects: X; X; It is necessary to create "suspended" values. These suspended X; values are represented as closures, which are in general heap X; allocated and expensive. X; X; For every level of recursion, new closures are created (h gets X; rebound above). While this could probably be optimized out by a X; smart compiler, it does seem like the representation of suspended X; evaluation by lambdas is inefficient. X; X; X; ######################################################################## X; X; You can try to figure out how all this works. It is complicated, I X; believe I understand it. The point in the derivation above is that in X; Scheme, to understand how the implementation of Y works, you have to X; fall back on the evaluation mechanism of Scheme. Suspended values must X; be represented as closures. It is the creation of these closures that X; cause the Scheme implementation to be slow. X; X; If one wishes to abandon Scheme (or at least applicative order X; evaluators of Scheme) one can typically do much better. My thesis work X; is in graph reduction, and trying to understand better the issues having X; to do with implementation. X; X; In graph reduction, all data items (evaluated and unevaluated) have the X; same representation: as graphs in the heap. We choose to evaluate using X; an outermost, leftmost strategy. This allows the natural definition of X; (Y h) = (h (Y h)) to be used. An application node of the form: X; X; @ X; / \ X; / \ X; Y h X; X; can be constructed in the obvious way: X; @ X; / \ X; / \ X; h @ X; / \ X; / \ X; Y h X; X; costing one heap allocation per level of recursion, which is X; certainly cheaper than the multiple allocations of scheme X; closures above. More efficiently, we might choose to implement X; it using a "knot tying" version: X; X; X; /\ X; / \ X; @ | X; / \ / X; / \/ X; h X; X; Which also works quite well. Y has been eliminated, and will X; cause no more reductions. X; X; The basic idea is somehow that recursion in functional languages X; is analogous to cycles in the graph in a graph reduction engine. X; Therefore, the Y combinator is a specific "textual" indicator of X; the graph. X; X; The G-machine (excellently described in Peyton Jones' book "The X; Implementation of Functional Programming Languages") also X; described the Y combinator as being efficient. He chose letrecs X; as being a primitive in the extended lambda calculus. His X; methodology behind compiling these recursive definitions was X; basically to compile fixed code which directly built these cyclic X; structures, rather than having them built at runtime. X; X; I think (and my thesis work is evolving into this kind of X; argument) that Y is overlooked for trivial reasons. Partial X; evaluation and smarter code generation could make an SK based X; compiler generate code which is equal in quality to that produced X; by supercombinator based compilation. X; X; X; This is too long already, ciao for now. X; X; Mark VandeWettering X X(print ((Y fact) 10)) END_OF_tst/Y if test 5985 -ne `wc -c <tst/Y`; then echo shar: \"tst/Y\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/cell -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/cell\" else echo shar: Extracting \"tst/cell\" \(563 characters\) sed "s/^X//" >tst/cell <<'END_OF_tst/cell' X;;; -*-Scheme-*- X X(define (make-cell) X (call-with-current-continuation X (lambda (return-from-make-cell) X (letrec ((state X (call-with-current-continuation X (lambda (return-new-state) X (return-from-make-cell X (lambda (op) X (case op X ((set) X (lambda (value) X (call-with-current-continuation X (lambda (return-from-access) X (return-new-state X (list value return-from-access)))))) X ((get) (car state))))))))) X ((cadr state) 'done))))) X X(define c (make-cell)) X(print ((c 'set) 99)) X(print (c 'get)) END_OF_tst/cell if test 563 -ne `wc -c <tst/cell`; then echo shar: \"tst/cell\" unpacked with wrong size! fi # end of overwriting check fi if test -f tst/co -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"tst/co\" else echo shar: Extracting \"tst/co\" \(2682 characters\) sed "s/^X//" >tst/co <<'END_OF_tst/co' X; -*-Scheme-*- X X(require 'cscheme) X X(define (displayLine . someArgs) X (for-each X (lambda (aTerm) (display aTerm) (display " ")) X someArgs) X (newline)) X X(define (Monitor) X X (define stopAtMonitorLevel #f) X (define clock 0) X (define stopTime 0) X (define processIndicators ()) X X (define (setInitialProcessState! aContinuation) X (set! processIndicators X (cons (list 0 aContinuation) processIndicators)) X (stopAtMonitorLevel #f)) X X (define (startSimulation! aDuration) X (set! stopTime aDuration) X (if (not (null? processIndicators)) X (let ((firstIndicatorOnList (car processIndicators))) X (set! processIndicators X (remove firstIndicatorOnList processIndicators)) X (resumeSimulation! firstIndicatorOnList)) X (displayLine "*** no active process recorded!"))) X X (define (resumeSimulation! aProcessState) X (set! processIndicators X (cons aProcessState processIndicators)) X (let ((nextProcessState aProcessState)) X (for-each (lambda (aStatePair) X (if (< (car aStatePair) (car nextProcessState)) X (set! nextProcessState aStatePair))) X processIndicators) X (let ((time (car nextProcessState)) X (continuation (cadr nextProcessState))) X (set! processIndicators X (remove nextProcessState processIndicators)) X (if (<= time stopTime) X (begin (set! clock time) X (continuation #f)) X (begin (displayLine "*** simulation stops at:" clock) X (stopAtMonitorLevel #f)))))) X X (define (dispatch aMessage . someArguments) X (cond ((eq? aMessage 'initialize) X (setInitialProcessState! (car someArguments))) X ((eq? aMessage 'startSimulation) X (startSimulation! (car someArguments))) X ((eq? aMessage 'proceed) X (resumeSimulation! (car someArguments))) X ((eq? aMessage 'time) X clock) X ((eq? aMessage 'processIndicators) X processIndicators) X (else X "Sorry, I don't know how to do this!"))) X X (call-with-current-continuation X (lambda (anArg) X (set! stopAtMonitorLevel anArg))) X dispatch) X X X X X(define (Tourist aName aMonitor) X (call-with-current-continuation X (lambda (anArg) X (aMonitor 'initialize anArg))) X (displayLine aName "starts at" (aMonitor 'time)) X (while #t X (displayLine aName "walks on at" (aMonitor 'time)) X (call-with-current-continuation X (lambda (anArg) X (aMonitor 'proceed X (list (+ (aMonitor 'time) 1) anArg)))) X (displayLine aName "arrives at new attraction at" (aMonitor 'time)) X (call-with-current-continuation X (lambda (anArg) X (aMonitor 'proceed X (list (+ (aMonitor 'time) 2) X anArg)))))) X X X(define Gallery (Monitor)) X X(Tourist 'Jane Gallery) X(Tourist 'Bruce Gallery) X X(Gallery 'startSimulation 5) END_OF_tst/co if test 2682 -ne `wc -c <tst/co`; then echo shar: \"tst/co\" unpacked with wrong size! fi # end of overwriting check fi if test ! -d lib ; then echo shar: Creating directory \"lib\" mkdir lib fi if test ! -d lib/xlib ; then echo shar: Creating directory \"lib/xlib\" mkdir lib/xlib fi if test ! -d lib/xlib/examples ; then echo shar: Creating directory \"lib/xlib/examples\" mkdir lib/xlib/examples fi if test -f lib/xlib/examples/lines -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"lib/xlib/examples/lines\" else echo shar: Extracting \"lib/xlib/examples/lines\" \(1096 characters\) sed "s/^X//" >lib/xlib/examples/lines <<'END_OF_lib/xlib/examples/lines' X;;; -*-Scheme-*- X X(require 'xlib) X X(define (lines) X (let* X ((dpy (open-display)) X (black (black-pixel dpy)) (white (white-pixel dpy)) X (win (make-window (parent (display-root-window dpy)) X (width 400) (height 400) X (background-pixel white) X (event-mask '(exposure button-press X enter-window leave-window)))) X (gc (make-gcontext (window win) (background white) X (foreground black))) X (draw X (lambda (inc) X (clear-window win) X (with win X (let ((width (window-width win)) X (height (window-height win))) X (do ((x 0 (+ x inc))) ((> x width)) X (draw-line win gc x 0 (- width x) height)) X (do ((y height (- y inc))) ((< y 0)) X (draw-line win gc 0 y width (- height y)))))))) X X (map-window win) X (unwind-protect X (handle-events dpy X (button-press X (lambda args #t)) X (expose X (lambda args X (draw 2) X #f)) X ((enter-notify leave-notify) X (lambda (e . args) X (set-window-border-pixel! win X (if (eq? e 'enter-notify) white black)) X #f))) X (close-display dpy)))) X X(lines) END_OF_lib/xlib/examples/lines if test 1096 -ne `wc -c <lib/xlib/examples/lines`; then echo shar: \"lib/xlib/examples/lines\" unpacked with wrong size! fi # end of overwriting check fi if test -f lib/xlib/examples/hello -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"lib/xlib/examples/hello\" else echo shar: Extracting \"lib/xlib/examples/hello\" \(1027 characters\) sed "s/^X//" >lib/xlib/examples/hello <<'END_OF_lib/xlib/examples/hello' X;;; -*-Scheme-*- X X(require 'xlib) X X(define (hello-world) X (let* ((dpy (open-display)) X (black (black-pixel dpy)) (white (white-pixel dpy)) X (font (open-font dpy "*-new century schoolbook-bold-r*24*")) X (text (translate-text "Hello world!")) X (width (+ (text-width font text '1-byte))) X (height (+ (max-char-ascent font) (max-char-descent font))) X (win (make-window (parent (display-root-window dpy)) X (width width) (height height) X (background-pixel white) X (event-mask '(exposure button-press)))) X (gc (make-gcontext (window win) (background white) X (foreground black) (font font)))) X (map-window win) X (unwind-protect X (handle-events dpy X (button-press X (lambda ignore #t)) X (expose X (lambda ignore X (let ((x (truncate (/ (- (window-width win) width) 2))) X (y (truncate (/ (- (+ (window-height win) X (max-char-ascent font)) X (max-char-descent font)) 2)))) X (draw-poly-text win gc x y text '1-byte)) #f))) X (close-display dpy)))) X X(hello-world) END_OF_lib/xlib/examples/hello if test 1027 -ne `wc -c <lib/xlib/examples/hello`; then echo shar: \"lib/xlib/examples/hello\" unpacked with wrong size! fi # end of overwriting check fi if test -f lib/xlib/examples/poly -a "${1}" != "-c" ; then echo shar: Will not over-write existing file \"lib/xlib/examples/poly\" else echo shar: Extracting \"lib/xlib/examples/poly\" \(976 characters\) sed "s/^X//" >lib/xlib/examples/poly <<'END_OF_lib/xlib/examples/poly' X;;; -*-Scheme-*- X X(require 'xlib) X X(define (poly) X (let* ((dpy (open-display)) X (black (black-pixel dpy)) (white (white-pixel dpy)) X (width 400) (height 400) X (win (make-window (parent (display-root-window dpy)) X (width width) (height height) X (background-pixel white) (event-mask '(exposure)))) X (gc (make-gcontext (window win) (function 'xor) X (background white) (foreground black))) X (l '(#f #f #f)) X (rand (lambda (x) (modulo (random) x)))) X (map-window win) X (handle-events dpy X (else (lambda args X (set! width (window-width win)) X (set! height (window-height win)) #t))) X (unwind-protect X (let loop ((n 0)) X (if (= n 200) X (begin X (clear-window win) X (display-wait-output dpy #f) X (set! n 0))) X (fill-polygon win gc X (list->vector X (map (lambda (x) (cons (rand width) (rand height))) l)) X #f 'convex) X (loop (1+ n))) X (close-display dpy)))) X X(poly) END_OF_lib/xlib/examples/poly if test 976 -ne `wc -c <lib/xlib/examples/poly`; then echo shar: \"lib/xlib/examples/poly\" unpacked with wrong size! fi # end of overwriting check fi echo shar: End of archive 8 \(of 14\). cp /dev/null ark8isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 14 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0