├── indexf.tex ├── leaf.gif ├── ref.tex ├── COPYING ├── epsfbox.tex ├── index.tex ├── toc.tex ├── README.adoc ├── obj.tex ├── title.tex ├── prng.tex ├── preface.tex ├── history ├── os.tex ├── table.tex ├── docmacro.tex ├── obj2.tex ├── dos.tex ├── if.tex ├── gamma.tex ├── mulinh.tex ├── hello.tex ├── form.tex ├── clock.tex ├── struct.tex ├── tyscheme.bib ├── umbrella.tex ├── io.tex ├── let.tex ├── rec.tex ├── script.tex ├── dialect.tex ├── obj1.tex ├── macro.tex ├── engine.tex ├── numint.tex ├── callcc.tex └── amb.tex /indexf.tex: -------------------------------------------------------------------------------- 1 | \chapter{Index} 2 | 3 | \inputindex 4 | -------------------------------------------------------------------------------- /leaf.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ds26gte/tyscheme/HEAD/leaf.gif -------------------------------------------------------------------------------- /ref.tex: -------------------------------------------------------------------------------- 1 | % last modified 2015-06-01 2 | \nocite{amop,eopl,htdp,keene,q:lisp,tls,tss,tspl} 3 | 4 | \chapter{References} 5 | \label{references} 6 | 7 | %\bibliographystyle{alpha} 8 | \bibliographystyle{plain} 9 | \bibliography{tyscheme} 10 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | Copyright (c) 1998-2015, Dorai Sitaram. 2 | All rights reserved. 3 | 4 | Permission to distribute and use this work for any 5 | purpose is hereby granted provided this copyright 6 | notice is included in the copy. This work is provided 7 | as is, with no warranty of any kind. 8 | -------------------------------------------------------------------------------- /epsfbox.tex: -------------------------------------------------------------------------------- 1 | %\texonly 2 | \ifx\epsfbox\UNDEFINED 3 | \ifx\pdfoutput\UNDEFINED 4 | \input epsf 5 | \else 6 | \ifx\convertMPtoPDF\UNDEFINED 7 | \expandafter\let 8 | \expandafter\epsfboxplusSAVE 9 | \csname\string+\endcsname 10 | \expandafter\def 11 | \csname\string+\endcsname{+}% 12 | \input supp-pdf 13 | \expandafter\let 14 | \csname\string+\endcsname 15 | \epsfboxplusSAVE 16 | \fi 17 | %\def\epsfbox#1{\convertMPtoPDF{#1}{1}{1}} 18 | \def\epsfbox#1{\convertMPtoPDF{#1}11} 19 | \fi 20 | \fi 21 | %\endtexonly 22 | -------------------------------------------------------------------------------- /index.tex: -------------------------------------------------------------------------------- 1 | \input docmacro 2 | 3 | \input title 4 | 5 | \input toc 6 | 7 | \input preface 8 | 9 | \input hello 10 | 11 | \input data 12 | 13 | \input form 14 | 15 | \input if 16 | 17 | \input let 18 | 19 | \input rec 20 | 21 | \input io 22 | 23 | \input macro 24 | 25 | \input struct 26 | 27 | \input table 28 | 29 | \input os 30 | 31 | \input obj 32 | 33 | \input callcc 34 | 35 | \input amb 36 | 37 | \input engine 38 | 39 | \input script 40 | 41 | \input cgi 42 | 43 | \appendix 44 | 45 | \input dialect 46 | 47 | \input dos 48 | 49 | \input numint 50 | 51 | \input clock 52 | 53 | \input ref 54 | 55 | \input indexf 56 | 57 | \bye 58 | -------------------------------------------------------------------------------- /toc.tex: -------------------------------------------------------------------------------- 1 | % last modified 2024-04-29 2 | \tag{tocpage}{-} 3 | %\htmlpagelabel{tocpage} 4 | 5 | %\beginsection \color{cc0000} Teach Yourself Scheme in 6 | %Fixnum Days 7 | 8 | \title{Teach Yourself Scheme in Fixnum Days} 9 | 10 | \smallskip 11 | 12 | \c{\copyright~\urlh{https://ds26gte.github.io}{Dorai 13 | Sitaram}, 1998--2024} 14 | \c{All Rights Reserved} 15 | \c{\p{ds26gte} {\em at} \p{yahoo.com}} 16 | \htmlonly 17 | \c{\urlh{http://ds26gte.github.io/tyscheme}{Document URL}} 18 | \c{\urlh{https://github.com/ds26gte/tyscheme}{[Download TeX source 19 | for this document]}} 20 | \c{Cover art by Margaret Wong} 21 | \endhtmlonly 22 | 23 | \bigskip 24 | 25 | \c{\bf Contents} 26 | 27 | \tableofcontents 28 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = tyscheme 2 | 3 | This archive contains the TeX source for the document _Teach 4 | Yourself Scheme in Fixnum Days_. It is written in plain-TeX 5 | format and uses a BibTeX bibliography. An HTML version may be 6 | browsed online at 7 | 8 | - http://ds26gte.github.io/tyscheme/index.html 9 | 10 | To get a PDF version of the document, run 11 | 12 | luatex index 13 | bibtex index 14 | makeindex index 15 | mpost numint 16 | luatex index 17 | luatex index 18 | 19 | The first tex run may cause an error because an 20 | EPS file is missing. Simply type `s` at the 21 | TeX prompt to force TeX to continue. 22 | 23 | The multiple runs of tex are needed to resolve 24 | cross-references. If the MetaPost executable 25 | is named `mp` on your system (e.g., MiKTeX), 26 | change `mpost` to `mp`. 27 | 28 | To get an HTML version of the document, run 29 | 30 | tex2page index 31 | 32 | a few times. As with TeX, multiple runs of tex2page 33 | are needed to resolve cross-references. Each run 34 | of tex2page will tell you if another run is necessary. 35 | 36 | The tex2page program is available at 37 | 38 | - https://github.com/ds26gte/tex2page 39 | 40 | ❧❧❧ 41 | 42 | Last modified: 2020-11-13 43 | -------------------------------------------------------------------------------- /obj.tex: -------------------------------------------------------------------------------- 1 | \chapter{Objects and classes} 2 | 3 | \index{object-oriented programming} 4 | \index{object} 5 | \index{class} 6 | \index{instance|see{object}} 7 | \index{method|see{object}} 8 | \index{slot|see{object}} 9 | A {\em class} describes a collection of {\em objects} 10 | that share behavior. The objects described by a class 11 | are called the {\em instances} of the class. The class 12 | specifies the names of the {\em slots} that the 13 | instance has, although it is up to the instance to 14 | populate these slots with particular values. 15 | The class also specifies the {\em methods} that can be 16 | applied to its instances. Slot values can be anything, 17 | but method values must be procedures. 18 | 19 | \index{subclass} 20 | \index{superclass} 21 | 22 | Classes are hierarchical. Thus, a class can be a {\em 23 | subclass} of another class, which is called its {\em 24 | superclass}. A subclass not only has its own {\em 25 | direct} slots and methods, but also inherits all the 26 | slots and methods of its superclass. If a class has a 27 | slot or method that has the same name as its 28 | superclass’s, then the subclass’s slot or method is the 29 | one that is retained. 30 | 31 | \input obj1.tex 32 | 33 | \input obj2.tex 34 | 35 | \input mulinh.tex 36 | -------------------------------------------------------------------------------- /title.tex: -------------------------------------------------------------------------------- 1 | %\externaltitle{Teach Yourself Scheme in Fixnum Days} 2 | \ifx\shipout\UnDeFiNeD 3 | \htmlonly 4 | \evalh{(do-end-para)} 5 | \rawhtml 6 | 7 | 11 |
12 | \endrawhtml 13 | {\bf\obeylines 14 | ~~~~~~~~~ 15 | ~~~~~~~~~ 16 | ~~~~~~~~~ 17 | ~~~~~~~~~ 18 | ~~~~~~~~~ 19 | ~~~~~~~~~~~~\hfnt{mediumvioletred}{2}{Teach} 20 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~\hfnt{crimson}{2}{Yourself} 21 | ~~~\hfnt{red}{8}{Scheme} 22 | ~~~\hfnt{darkorange}{1}{in} 23 | ~~~~~~~~~~~~~~~~~~~\hfnt{orangered}{1}{Fixnum} 24 | ~~~~~~~~~~~~~~~~~~~~~~\hfnt{purple}{1}{Days} 25 | ~~~~~~~~~ 26 | ~~~~~~~~~ 27 | \htmladdimg{leaf.gif} 28 | ~~~~~~~~~ 29 | ~~~~~~~~~ 30 | ~~~~~~~~~~~~\hfnt{darkgreen}{1}{by} 31 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\hfnt{darkblue}{1}{Dorai Sitaram} 32 | ~~~~~~~~~ 33 | ~~~~~~~~~ 34 | ~~~~~~~~~ 35 | ~~~~~~~~~ 36 | ~~~~~~~~~ 37 | ~~~~~~~~~ 38 | ~~~~~~~~~ 39 | ~~~~~~~~~ 40 | ~~~~~~~~~ 41 | ~~~~~~~~~ 42 | ~~~~~~~~~ 43 | } 44 | \rawhtml 45 |
46 | \endrawhtml 47 | \endhtmlonly 48 | 49 | \htmlheadonly 50 | 52 | 53 | 54 | 55 | 56 | \endhtmlheadonly 57 | \fi 58 | \eject 59 | -------------------------------------------------------------------------------- /prng.tex: -------------------------------------------------------------------------------- 1 | \section{Pseudorandom-number generators} 2 | 3 | \index{random@\q{random}} 4 | \index{random-number generator} 5 | \index{pseudorandom-number generator} 6 | We see that unlike \q{add2}, the procedure \q{bump-counter} 7 | returns a different result each time it’s called, because it 8 | side-effects something outside itself. One particularly useful 9 | variant of this procedure generates a different {\em random} 10 | number each time it’s called. Many Schemes provide this as a 11 | primitive procedure called \q{random}\f{Writing your own version 12 | of \q{random} in Scheme requires quite a bit of mathematical 13 | chops to get something acceptable. We won’t get into that here.}: 14 | When called with no argument, \q{(random)} returns a 15 | “pseudorandom” number in the interval [0, 1), i.e., between 0 16 | (inclusive) and 1 (exclusive), such that the results are 17 | uniformly distributed within that interval. 18 | 19 | \q{ 20 | (random) |evalsto 0.6360226737551197 21 | (random) |evalsto 0.8057127493871963 22 | (random) |evalsto 0.8595213305159558 23 | } 24 | 25 | \n With only a little bit of arithmetic, \q{random} can be used 26 | to simulate events of known probability. Consider the throwing of 27 | a fair, six-headed die: The outcomes 1, 2, 3, 4, 5, 6 are equally 28 | likely. To simulate this, we divide the interval [0, 1) into six 29 | equal segments, associate each segment with an outcome, and have 30 | \q{(random)}’s output decide which outcome occurred. One way to 31 | do it is to multiply the random number $n$ ($0 \le n < 1$) by 6 32 | and take the ceiling: I'll leave you to convince yourself that 33 | this takes on the value of each die face with 1/6 probability. 34 | 35 | \scmfilename dice.scm 36 | 37 | \scmdribble{ 38 | (define throw-one-die 39 | (lambda () 40 | (let ((result (ceiling (* (random) 6)))) 41 | result))) 42 | } 43 | 44 | \n \q{throw-two-dice} simply calls \q{throw-one-die} twice: 45 | 46 | \scmdribble{ 47 | 48 | (define throw-two-dice 49 | (lambda () 50 | (+ (throw-one-die) (throw-one-die)))) 51 | } 52 | 53 | \n It returns an integer between 2 and 12 inclusive — not all 54 | equally likely! 55 | -------------------------------------------------------------------------------- /preface.tex: -------------------------------------------------------------------------------- 1 | \chapter*{Preface} 2 | 3 | This is an introduction to the Scheme programming 4 | language. It is intended as a quick-start guide, 5 | something a novice can use to get a non-trivial working 6 | knowledge of the language, before moving on to more 7 | comprehensive and in-depth texts. 8 | 9 | The text describes {\em an} approach to writing a crisp 10 | and utilitarian Scheme. Although we will not cover 11 | Scheme from \q{abs} to \q{zero?}, we will not shy away 12 | from those aspects of the language that are difficult, 13 | messy, nonstandard, or unusual, but nevertheless useful 14 | and usable. Such aspects include 15 | \q{call-with-current-continuation}, system 16 | interface, and dialect diversity. Our 17 | discussions will be informed by our focus on 18 | problem-solving, not by a quest for metalinguistic 19 | insight. I have therefore left out many of the staples 20 | of traditional Scheme tutorials. There will be no 21 | in-depth pedagogy; no dwelling on the semantic appeal 22 | of Scheme; no metacircular interpreters; no discussion 23 | of the underlying implementation; 24 | and no evangelizing about Scheme’s virtues. This is 25 | not to suggest that these things are unimportant. 26 | However, they are arguably not immediately relevant to 27 | someone seeking a quick introduction. 28 | 29 | \index{R5RS} 30 | \index{fixnum} 31 | \index{zen} 32 | 33 | How quick though? I do not know if one can teach 34 | oneself Scheme in 21 days\f{A {\em fixnum} is a 35 | machine’s idea of a “small” integer. Every machine 36 | has its own idea of how big a fixnum can be.}, although 37 | I have heard it said that the rudiments of Scheme 38 | should be a matter of an afternoon’s study. The Scheme 39 | standard \cite{r5rs} itself, for all its exacting 40 | comprehensiveness, is a mere fifty pages long. It may 41 | well be that the insight, when it comes, will arrive in 42 | its entirety in one afternoon, though there is no 43 | telling how many afternoons of mistries must precede 44 | it. Until that zen moment, here is my gentle 45 | introduction. 46 | 47 | {\em Acknowledgment.} I thank Matthias Felleisen for 48 | introducing me to Scheme and higher-order programming; 49 | and Matthew Flatt for creating the robust and 50 | pleasant MzScheme implementation used throughout this 51 | book. 52 | 53 | \texonly 54 | \bigbreak 55 | \endtexonly 56 | 57 | —d 58 | 59 | -------------------------------------------------------------------------------- /history: -------------------------------------------------------------------------------- 1 | Nov 18, 2004 2 | 3 | Replace raw HTML sourcing of leaf.gif image with \htmladdimg. This allows 4 | image to be copied automatically to target directory (when latter is 5 | different from working directory). Prob reported by Paul Bolle (pebolle at 6 | tiscali dot nl). 7 | 8 | Dec 4, 2003 9 | 10 | Use (amb #f #t) instead of (amb #t #f) to better show that backtracking 11 | occurs in (if (amb #f #t) 1 (amb)). Suggested by Shriram 12 | Krishnamurthi. 13 | 14 | Aug 26, 2003 15 | 16 | Typo fix: s/get or put/get or post/. Reported by 17 | Nobuo Yamashita (nobsun @ sampou.org). 18 | 19 | Aug 14, 2003 20 | 21 | 2.2.1 hello typo fix (Aaron.Hawley @ uvm.edu). 22 | 23 | Mar 11, 2003 24 | 25 | Use +local-control-state in coroutine macro def, 26 | because it should rightly be a gensym. (Ivan Toshkov) 27 | 28 | Jan 3, 2003 29 | 30 | added metapost picture for simpson's rule 31 | 32 | Dec 7, 2002 33 | 34 | Improve presentation of dialect invocation 35 | command and init files. Add Chicken. 36 | 37 | Nov 30, 2002 38 | 39 | Update macro definition description for 40 | MIT Scheme v 7.7.1 41 | 42 | Nov 17, 2002 43 | 44 | Added makefile for my own use. 45 | 46 | 25 Oct 2002 47 | 48 | Typo in code example in script.tex. 49 | 50 | 11 Dec 2001 51 | 52 | Modifications to reflect MzScheme changes as it moves 53 | to v200. Input from Matthew Flatt. 54 | 55 | 28 Nov 2001 56 | 57 | string-set! only works on non-constant strings! 58 | Error pointed out by Charles Hixson. 59 | 60 | Corrected silly 'if' example bug spotted by Kelly Gerber. 61 | 62 | 8 Oct 2001 63 | 64 | Add treatment of improper integrals with 65 | Gamma function as example 66 | 67 | 1 Oct 2001 68 | 69 | Refine integrate-adaptive-simpson to reuse 70 | ordinate calculations when possible 71 | 72 | 30 Sep 2001 73 | 74 | Put numerical integration example in an appendix. 75 | Add integrate-adaptive-simpson to the example. 76 | 77 | 23 Sep 2001 78 | 79 | Added an impl of Simpson's rule as an example of 80 | iteration in the service of number-crunching. 81 | 82 | 5 Feb 2001 83 | 84 | Matthias Felleisen corrects me on (rational? 85 | 3.1416), which is true not false. In other words, 86 | there is no real (!) difference between the set of 87 | Scheme real numbers and the set of Scheme rational 88 | numbers... 89 | 90 | Dec 9, 2000 91 | 92 | Added index. Requested by Robert Bruce Findler. 93 | 94 | ; 95 | 96 | Apr 2000 97 | 98 | ; 99 | 100 | (added objects, amb) 101 | 102 | ; 103 | 104 | 6 Mar 1999 105 | 106 | announced publicly 107 | 108 | Mar/Apr 1998 109 | 110 | on web 111 | -------------------------------------------------------------------------------- /os.tex: -------------------------------------------------------------------------------- 1 | \chapter{System interface} 2 | \label{os} 3 | 4 | Useful Scheme programs often need to interact with the 5 | underlying operating system. 6 | 7 | %Separate filesystem 8 | %interface from here? Aren’t Scheme I/O procs also 9 | %filesystem interfacers? Maybe I should call this the 10 | %_non_-standard part of Scheme’s OS interface 11 | 12 | \section{Checking for and deleting files} 13 | 14 | \index{file!checking existence of} 15 | \index{file!deleting} 16 | \index{file-exists?@\q{file-exists?}} 17 | \index{delete-file@\q{delete-file}} 18 | \q{file-exists?} checks if its argument string names 19 | a file. \q{delete-file} deletes its argument file. 20 | These procedures are not part of the Scheme standard, 21 | but are available in most implementations. These 22 | procedures work reliably only for files that are not 23 | directories. (Their behavior on directories is 24 | dialect-specific.) 25 | 26 | \index{file!time of last modification of} 27 | \index{file-or-directory-modify-seconds@\q{file-or-directory-modify-seconds}} 28 | 29 | \q{file-or-directory-modify-seconds} returns the time when its 30 | argument file or directory was last modified. Time is 31 | reckoned in seconds from 12 AM GMT, 1 January 1970. 32 | E.g., 33 | 34 | \q{ 35 | (file-or-directory-modify-seconds "hello.scm") 36 | |evalsto 893189629 37 | } 38 | 39 | \n assuming that the file \p{hello.scm} was last messed with 40 | sometime on 21 April 1998. 41 | 42 | \section{Calling operating-system commands} 43 | 44 | \index{system@\q{system}} 45 | The \q{system} procedure executes its argument string 46 | as an operating-system command.\f{MzScheme provides the 47 | \q{system} procedure via the \p{process} library. Use \q{(require 48 | (lib "process.ss"))} to load this library.} It returns true if the 49 | command executed successfully with an exit status 0, 50 | and false if it failed to execute or exited with a 51 | non-zero status. Any output generated by the command 52 | goes to standard output. 53 | 54 | \q{ 55 | (system "ls") 56 | ;lists current directory 57 | 58 | (define fname "spot") 59 | 60 | (system (string-append "test -f " fname)) 61 | ;tests if file ‘spot’ exists 62 | 63 | (system (string-append "rm -f " fname)) 64 | ;removes ‘spot’ 65 | } 66 | 67 | The last two forms are equivalent to 68 | 69 | \q{ 70 | (file-exists? fname) 71 | 72 | (delete-file fname) 73 | } 74 | 75 | \section{Environment variables} 76 | 77 | \index{getenv@\q{getenv}} 78 | The \q{getenv} procedure returns the setting of an 79 | operating-system environment variable. E.g., 80 | 81 | \q{ 82 | (getenv "HOME") 83 | |evalsto "/home/dorai" 84 | 85 | (getenv "SHELL") 86 | |evalsto "/bin/bash" 87 | } 88 | 89 | -------------------------------------------------------------------------------- /table.tex: -------------------------------------------------------------------------------- 1 | \chapter{Alists and tables} 2 | 3 | \index{association list|see{alist}} 4 | \index{alist} 5 | An {\em association list}, or {\em alist}, is a Scheme 6 | list of a special format. Each element of the list is 7 | a cons cell, the car of which is called a {\em key}, 8 | the cdr being the {\em value} associated with the key. 9 | E.g., 10 | 11 | \q{ 12 | ((a . 1) (b . 2) (c . 3)) 13 | } 14 | 15 | \index{assv@\q{assv}} 16 | 17 | The procedure call \q{(assv k al)} finds the cons cell 18 | associated with key \q{k} in alist \q{al}. The keys of 19 | the alist are compared against the given \q{k} using 20 | the equality predicate \q{eqv?}. In general, though we 21 | may want a different predicate for key comparison. For 22 | instance, if the keys were case-insensitive strings, 23 | the predicate \q{eqv?} is not very useful. 24 | 25 | \index{table} 26 | 27 | We now define a structure called \q{table}, which is a 28 | souped-up alist that allows user-defined predicates on 29 | its keys. Its fields are \q{equ} and \q{alist}. 30 | 31 | \scmfilename table.scm 32 | 33 | \scmwrite{ 34 | (load-relative "defstruct.scm") 35 | } 36 | 37 | \scmdribble{ 38 | (defstruct table (equ eqv?) (alist '())) 39 | } 40 | 41 | \n (The default predicate is \q{eqv?} — as for an 42 | ordinary alist — and the alist is initially empty.) 43 | 44 | We will use the procedure \q{table-get} to get the 45 | value (as opposed to the cons cell) associated with a 46 | given key. \q{table-get} takes a table and key 47 | arguments, followed by an optional default value that 48 | is returned if the key was not found in the table: 49 | 50 | \scmdribble{ 51 | (define table-get 52 | (lambda (tbl k . d) 53 | (let ((c (lassoc k (table.alist tbl) (table.equ tbl)))) 54 | (cond (c (cdr c)) 55 | ((pair? d) (car d)))))) 56 | } 57 | 58 | The procedure \q{lassoc}, used in \q{table-get}, is 59 | defined as: 60 | 61 | \scmdribble{ 62 | (define lassoc 63 | (lambda (k al equ?) 64 | (let loop ((al al)) 65 | (if (null? al) #f 66 | (let ((c (car al))) 67 | (if (equ? (car c) k) c 68 | (loop (cdr al)))))))) 69 | } 70 | 71 | The procedure \q{table-put!} is used to update a key’s 72 | value in the given table: 73 | 74 | \scmdribble{ 75 | (define table-put! 76 | (lambda (tbl k v) 77 | (let ((al (table.alist tbl))) 78 | (let ((c (lassoc k al (table.equ tbl)))) 79 | (if c (set-cdr! c v) 80 | (set!table.alist tbl (cons (cons k v) al))))))) 81 | } 82 | 83 | The procedure \q{table-for-each} calls the given 84 | procedure on every key/value pair in the table 85 | 86 | \scmdribble{ 87 | (define table-for-each 88 | (lambda (tbl p) 89 | (for-each 90 | (lambda (c) 91 | (p (car c) (cdr c))) 92 | (table.alist tbl)))) 93 | } 94 | 95 | 96 | 97 | 98 | -------------------------------------------------------------------------------- /docmacro.tex: -------------------------------------------------------------------------------- 1 | %\input slatex.sty 2 | 3 | %\slatexdisable{enableslatex} 4 | \ifx\shipout\UnDeFiNeD\else 5 | \input tex2page 6 | \input plainsection 7 | \input tgtermes 8 | \input btxmac 9 | 10 | 11 | \input miniltx 12 | \input color.sty 13 | 14 | \resetatcatcode 15 | 16 | \ifx\epsfbox\undefineD 17 | \def\epsfbox#1{\convertMPtoPDF{#1}{1}{1}}% 18 | \fi 19 | 20 | %\inputepsf 21 | 22 | %\enableslatex 23 | 24 | \plaintextweaks 25 | \fi 26 | 27 | \let\tag\xrtag 28 | 29 | % www.w3.org/StyleSheets/Core/{Chocolate, Midnight, 30 | % Modernist, Oldstyle, Steely, Swiss, Traditional, 31 | % Ultramarine} 32 | 33 | %\inputcss http://www.w3.org/StyleSheets/Core/Oldstyle 34 | 35 | \overfullrule 0pt 36 | 37 | \let\c\centerline 38 | \let\o\item 39 | \let\f\numberedfootnote 40 | \let\n\noindent 41 | \let\p\verb 42 | %\let\pp\p 43 | \let\q\scm 44 | \let\scmfilename\verbwritefile 45 | \let\scmwrite\verbwrite 46 | %\let\qq\q 47 | 48 | \def\{{{\tt\char`\{}} 49 | \def\}{{\tt\char`\}}} 50 | 51 | \texonly 52 | %\input 2col 53 | %\input ptm 54 | \sidemargin 1.75 true in 55 | %\nocapdot 56 | \def\evalsto{$\Rightarrow$ } 57 | \def\causeserror{$\rightarrow${\em ERROR!!!}} 58 | \def\eqv{\leavevmode\hbox{$\equiv$}} 59 | %\let\byline\centerline 60 | 61 | \def\robust#1{\global\let\robustcmd#1% 62 | \begingroup 63 | \def\do##1{\catcode`##1=9 }\dospecials 64 | \catcode`\{1 \catcode`\}2 65 | \robustI} 66 | 67 | \def\robustI#1{\endgroup 68 | \robustcmd} 69 | 70 | \ifx\slatexversion\UNDEFINED\else 71 | %\defschemetoken{q} 72 | \setspecialsymbol{|evalsto}{$\Longrightarrow$} 73 | \setspecialsymbol{|causeserror}{$\rightarrow${\em ERROR!!!}} 74 | \fi 75 | 76 | \endtexonly 77 | 78 | %\def\em{*\aftergroup\endem} 79 | %\let\endem* 80 | 81 | \ifx\shipout\UNDEFINED 82 | \htmlonly 83 | 84 | \cssblock 85 | body { 86 | max-width: 450pt; 87 | } 88 | \endcssblock 89 | 90 | \imgpreamble 91 | \magnification\magstep2 92 | \endimgpreamble 93 | 94 | \dontuseimgforhtmlmathintext 95 | 96 | %\imgdef\pi{$\pi$} 97 | %\imgdef\int{$\int$} 98 | %\def\{{\rawhtml{\endrawhtml} 99 | %\def\}{\rawhtml}\endrawhtml} 100 | %\def\it{\color{blue}} 101 | %\def\em{\color{blue}} 102 | \def\evalsto{{\color[named]{teal}\tt\bf=>} } 103 | \def\causeserror{{\color[named]{red}\tt\bf\it-->ERROR!!!}} 104 | \def\eqv{==} 105 | \let\byline\leftline 106 | 107 | \def\robust#1#2#3{#1{#2}} 108 | 109 | \def\hfnt#1#2#3{\rawhtml 111 | \endrawhtml #3 \rawhtml 112 | \endrawhtml} 113 | 114 | \evalh{ 115 | (if 'nil 116 | (for-each 117 | make-reusable-math-image-as-needed 118 | '( 119 | "\\infty" 120 | "\\int" 121 | "\\Gamma" 122 | "\\pi" 123 | "\\phi" 124 | )) 125 | (mapc 126 | (function make-reusable-math-image-as-needed) 127 | '( 128 | "\\infty" 129 | "\\int" 130 | "\\Gamma" 131 | "\\pi" 132 | "\\phi" 133 | ))) 134 | } 135 | 136 | \endhtmlonly 137 | \fi 138 | 139 | \scmkeyword{amb bag-of coroutine stk%define-macro} 140 | -------------------------------------------------------------------------------- /obj2.tex: -------------------------------------------------------------------------------- 1 | \scmfilename obj2.scm 2 | 3 | \scmwrite{ 4 | (load-relative "obj1.scm") 5 | } 6 | 7 | \section{Classes are instances too} 8 | 9 | \index{metaclass} 10 | It cannot have escaped the astute reader that classes 11 | themselves look like they could be the instances of 12 | some class (a {\em metaclass}, if you will). Note that 13 | all classes have some common behavior: each of them has 14 | slots, a superclass, a list of method names, and a 15 | method vector. \q{make-instance} looks like it could 16 | be their shared method. This suggests that we could 17 | specify this common behavior by another class (which 18 | itself should, of course, be a class instance too). 19 | 20 | In concrete terms, we could rewrite our class 21 | implementation to itself make use of the 22 | object-oriented approach, provided we make sure we 23 | don’t run into chicken-and-egg problems. In effect, we 24 | will be getting rid of the \q{class} struct and its 25 | attendant procedures and rely on the rest of the 26 | machinery to define classes as objects. 27 | 28 | Let us identify \q{standard-class} as the class of 29 | which other classes are instances of. In particular, 30 | \q{standard-class} must be an instance of itself. What 31 | should \q{standard-class} look like? 32 | 33 | We know \q{standard-class} is an instance, and we are 34 | representing instances by vectors. So it is a 35 | vector whose first element holds its class, i.e., 36 | itself, and whose remaining elements are slot values. 37 | We have identified four slots that all classes must 38 | have, so \q{standard-class} is a 5-element vector. 39 | 40 | \scmdribble{ 41 | (define standard-class 42 | (vector 'value-of-standard-class-goes-here 43 | (list 'slots 44 | 'superclass 45 | 'method-names 46 | 'method-vector) 47 | #t 48 | '(make-instance) 49 | (vector make-instance))) 50 | } 51 | 52 | \n Note that the \q{standard-class} vector is 53 | incompletely filled in: the symbol 54 | \q{value-of-standard-class-goes-here} functions as a 55 | placeholder. Now that we have defined a 56 | \q{standard-class} value, we can use it to identify its 57 | own class, which is itself: 58 | 59 | \scmdribble{ 60 | (vector-set! standard-class 0 standard-class) 61 | } 62 | 63 | Note that we cannot rely on procedures based on the 64 | \q{class} struct anymore. We should replace all calls 65 | of the form 66 | 67 | \q{ 68 | (standard-class? x) 69 | (standard-class.slots c) 70 | (standard-class.superclass c) 71 | (standard-class.method-names c) 72 | (standard-class.method-vector c) 73 | (make-standard-class ...) 74 | } 75 | 76 | \n by 77 | 78 | \q{ 79 | (and (vector? x) (eqv? (vector-ref x 0) standard-class)) 80 | (vector-ref c 1) 81 | (vector-ref c 2) 82 | (vector-ref c 3) 83 | (vector-ref c 4) 84 | (send 'make-instance standard-class ...) 85 | } 86 | 87 | \scmwrite{ 88 | (define (standard-class? x) 89 | (and (vector? x) (eqv? (vector-ref x 0) standard-class))) 90 | (define (standard-class.slots c) (vector-ref c 1)) 91 | (define (standard-class.superclass c) (vector-ref c 2)) 92 | (define (standard-class.method-names c) (vector-ref c 3)) 93 | (define (standard-class.method-vector c) (vector-ref c 4)) 94 | (define (make-standard-class . args) 95 | (apply send 'make-instance standard-class args)) 96 | } 97 | -------------------------------------------------------------------------------- /dos.tex: -------------------------------------------------------------------------------- 1 | \chapter{DOS batch files in Scheme} 2 | \label{dos} 3 | 4 | \index{script!DOS} 5 | DOS shell scripts are known as {\em batch files}. A 6 | conventional DOS batch file that outputs “Hello, 7 | World!”\ has the following contents: 8 | 9 | \p{ 10 | echo Hello, World! 11 | } 12 | 13 | It uses the DOS command \p{echo}. The batch file is 14 | named \p{hello.bat}, which identifies it to the 15 | operating system as an executable. It may then be 16 | placed in one of the directories on the \p{PATH} 17 | environment variable. Thereafter, anytime one types 18 | 19 | \p{ 20 | hello.bat 21 | } 22 | 23 | or simply 24 | 25 | \p{ 26 | hello 27 | } 28 | 29 | \n at the DOS prompt, one promptly gets the 30 | insufferable greeting. 31 | 32 | A Scheme version of the hello batch file will perform 33 | the same output using Scheme, but we need something in 34 | the file to inform DOS that it needs to construe the 35 | commands in the file as Scheme, and not as its default 36 | batch language. The Scheme batch file, also called 37 | \p{hello.bat}, looks like: 38 | 39 | \p+ 40 | ;@echo off 41 | ;goto :start 42 | #| 43 | :start 44 | echo. > c:\_temp.scm 45 | echo (load (find-executable-path "hello.bat" >> c:\_temp.scm 46 | echo "hello.bat")) >> c:\_temp.scm 47 | mzscheme -r c:\_temp.scm %1 %2 %3 %4 %5 %6 %7 %8 %9 48 | goto :eof 49 | |# 50 | 51 | (display "Hello, World!") 52 | (newline) 53 | 54 | ;:eof 55 | + 56 | 57 | The lines upto \p+|#+ are standard DOS batch. Then 58 | follows the Scheme code for the greeting. Finally, 59 | there is one more standard DOS batch line, viz., 60 | \p{;:eof}. 61 | 62 | When the user types \p{hello} at the DOS prompt, DOS 63 | reads and runs the file \p{hello.bat} as a regular 64 | batch file. The first line, \p{;@echo off}, turns off 65 | the echoing of the commands run — as we don’t want 66 | excessive verbiage clouding the effect of our script. 67 | The second line, \p{;goto :start}, causes execution to 68 | jump forward to the line labeled \p{:start}, i.e., the 69 | fourth line. The three ensuing \p{echo} lines create a 70 | temporary Scheme file called \p{c:\_temp.tmp} with the 71 | following contents: 72 | 73 | \q{ 74 | (load (find-executable-path "hello.bat" "hello.bat")) 75 | } 76 | 77 | The next batch command is a call to MzScheme. The 78 | \p{-r} option loads the Scheme file \p{c:\_temp.scm}. 79 | All the arguments (in this example, none) will be 80 | available to Scheme in the vector \q{argv}. This call 81 | to Scheme will evaluate our Scheme script, as we will 82 | see below. After Scheme returns, we still need to 83 | ensure that the batch file winds up cleanly. The next 84 | batch command is \p{goto :eof}, which causes 85 | control to skirt all the Scheme code and go to the very 86 | end of the file, which contains the label 87 | \p{;:eof}. The script thus ends. 88 | 89 | Now we can see how the call to Scheme does its part, 90 | viz., to run the Scheme expressions embedded in the 91 | batch file. Loading \p{c:\_temp.scm} will cause Scheme 92 | to deduce the full pathname of the file \p{hello.bat} 93 | (using \q{find-executable-path}), and to then {\em 94 | load} 95 | \p{hello.bat}. 96 | 97 | Thus, the Scheme script file will now be run as a 98 | Scheme file, and the Scheme forms in the file will have 99 | access to the script’s original arguments via the 100 | vector \q{argv}. 101 | 102 | Now, Scheme has to skirt the batch commands in the 103 | script. This is easily done because these batch 104 | commands are either prefixed with a semicolon or are 105 | enclosed in \p+#| ... |#+, making them Scheme comments. 106 | 107 | The rest of the file is of course straight Scheme, and 108 | the expressions therein are evaluated in sequence. (The 109 | final expression, \p{;:eof}, is a Scheme comment, and 110 | causes no harm.) After all the expressions have been 111 | evaluated, Scheme will exit. 112 | 113 | In sum, typing \p{hello} at the DOS prompt will produce 114 | 115 | \p{ 116 | Hello, World! 117 | } 118 | 119 | \n and return you to the DOS prompt. 120 | -------------------------------------------------------------------------------- /if.tex: -------------------------------------------------------------------------------- 1 | \chapter{Conditionals} 2 | 3 | \index{if@\q{if}} 4 | \index{conditional} 5 | Like all languages, Scheme provides {\em 6 | conditionals}. The basic form is the \q{if}: 7 | 8 | \q{ 9 | (if test-expression 10 | then-branch 11 | else-branch) 12 | } 13 | 14 | If \q{test-expression} evaluates to true (i.e., any value 15 | other than \q{#f}), the “then” branch is evaluated. 16 | If not, the “else” branch is evaluated. The 17 | “else” branch is optional. 18 | 19 | \q{ 20 | (define p 80) 21 | 22 | (if (> p 70) 23 | 'safe 24 | 'unsafe) 25 | |evalsto safe 26 | 27 | (if (< p 90) 28 | 'low-pressure) ;no “else” branch 29 | |evalsto low-pressure 30 | } 31 | 32 | Scheme provides some other conditional forms for 33 | convenience. They can all be defined as macros 34 | (chapter~\ref{sugar}) that expand 35 | into \q{if}-expressions. 36 | 37 | \index{when@\q{when}} 38 | \index{unless@\q{unless}} 39 | 40 | \section{\q{when} and \q{unless}} 41 | 42 | \q{when} and \q{unless} are convenient conditionals 43 | to use when only one branch (the “then” or the 44 | “else” branch) of the basic conditional is needed. 45 | 46 | \q{ 47 | (when (< (pressure tube) 60) 48 | (open-valve tube) 49 | (attach floor-pump tube) 50 | (depress floor-pump 5) 51 | (detach floor-pump tube) 52 | (close-valve tube)) 53 | } 54 | 55 | Assuming \q{pressure} of \q{tube} is less than 56 | \q{60}, this conditional will attach \q{floor-pump} to 57 | \q{tube} and \q{depress} it \q{5} times. (\q{attach} 58 | and \q{depress} are some suitable procedures.) 59 | 60 | The same program using \q{if} would be: 61 | 62 | \q{ 63 | (if (< (pressure tube) 60) 64 | (begin 65 | (open-valve tube) 66 | (attach floor-pump tube) 67 | (depress floor-pump 5) 68 | (detach floor-pump tube) 69 | (close-valve tube))) 70 | } 71 | 72 | \index{begin@\q{begin}!implicit} 73 | 74 | Note that \q{when}’s branch is an implicit \q{begin}, 75 | whereas \q{if} requires an explicit \q{begin} if either 76 | of its branches has more than one form. 77 | 78 | The same behavior can be written using \q{unless} as 79 | follows: 80 | 81 | \q{ 82 | (unless (>= (pressure tube) 60) 83 | (open-valve tube) 84 | (attach floor-pump tube) 85 | (depress floor-pump 5) 86 | (detach floor-pump tube) 87 | (close-valve tube)) 88 | } 89 | 90 | \n Not all Schemes provide \q{when} and \q{unless}. 91 | If your Scheme does not have them, you can 92 | define them as macros (see chapter~\ref{sugar}). 93 | 94 | \index{cond@\q{cond}} 95 | \section{\q{cond}} 96 | 97 | The \q{cond} form is convenient for expressing nested 98 | \q{if}-expressions, where each “else” branch but the last 99 | introduces a new \q{if}. Thus, the form 100 | 101 | \q{ 102 | (if (char 0$, $\Gamma(n)$ is defined as the 12 | following integral with unbounded upper limit: 13 | 14 | $$ \Gamma(n) = \int_0^{\infty} x^{n-1}e^{-x} dx $$ 15 | % 16 | From this, it follows that (a) $\Gamma(1) = 1$, and (b) 17 | for $n > 0$, $\Gamma(n+1) = n\Gamma(n)$. This implies 18 | that if we know the value of $\Gamma$ in the interval 19 | $(1, 2)$, we can find $\Gamma(n)$ for any {\em real} $n > 0$. 20 | Indeed, if we relax the condition $n > 0$, we can use 21 | result (b) to extend the domain of $\Gamma(n)$ to 22 | include $n \le 0$, with the understanding that the function 23 | will diverge for {\em integer} $n \le 0$.\f{$\Gamma(n)$ for real $n > 0$ is 24 | itself an extension of the “decrement-then-factorial” function 25 | that maps {\em integer} $n > 0$ to $(n-1)!$.} 26 | 27 | We first implement a Scheme procedure \q{gamma-1-to-2} 28 | that requires its argument \q{n} to be within the 29 | interval $(1, 2)$. \q{gamma-1-to-2} takes a 30 | second argument \q{e} for the tolerance. 31 | 32 | \scmdribble{ 33 | (define gamma-1-to-2 34 | (lambda (n e) 35 | (unless (< 1 n 2) 36 | (error 'gamma-1-to-2 "argument outside (1, 2)")) 37 | ;... 38 | } 39 | 40 | \n 41 | We introduce a local variable \q{gamma-integrand} to hold 42 | the $\Gamma$-integrand $g(x) = x^{n-1}e^x$: 43 | 44 | \scmdribble{ 45 | ;... 46 | (let ((gamma-integrand 47 | (let ((n-1 (- n 1))) 48 | (lambda (x) 49 | (* (expt x n-1) 50 | (exp (- x)))))) 51 | ;... 52 | } 53 | 54 | \n We now need to integrate $g(x)$ from 0 to $\infty$. 55 | Clearly we cannot deal with an infinite number of 56 | intervals; we therefore use Simpson’s rule for only a 57 | portion of the interval $[0, \infty)$, say $[0, x_c]$ 58 | ($c$ for “cut-off”). For the remaining, “tail”, 59 | interval $[x_c, \infty)$, we use a tail-integrand 60 | $t(x)$ that reasonably approximates $g(x)$, but has the 61 | advantage of being more tractable to analytic solution. 62 | Indeed, it is easy to see that for sufficiently large 63 | $x_c$, we can replace $g(x)$ by an exponential decay 64 | function $t(x) = y_c e^{-(x - x_c )}$, where $y_c 65 | = g(x_c)$. Thus: 66 | 67 | $$ 68 | \int_0^{\infty} g(x) dx \approx 69 | \int_0^{x_c} g(x) dx + 70 | \int_{x_c}^{\infty} t(x) dx 71 | $$ 72 | % 73 | The first integral can be solved using Simpson’s rule, 74 | and the second integral is just $y_c$. To find $x_c$, 75 | we start with a low-ball value (say 4), and then refine 76 | it by successively doubling it until the ordinate at 77 | $2x_c$ (i.e., $g(2x_c)$) is within a certain 78 | tolerance of the ordinate predicted by the tail-integrand 79 | (i.e., $t(2x_c)$). For both the Simpson 80 | integral and the tail-integrand calculation, we will 81 | require a tolerance of \q{e/100}, an order of 2 less than 82 | the given tolerance \q{e}, so the overall 83 | tolerance is not affected: 84 | 85 | \scmdribble{ 86 | ;... 87 | (e/100 (/ e 100))) 88 | (let loop ((xc 4) (yc (gamma-integrand 4))) 89 | (let* ((tail-integrand 90 | (lambda (x) 91 | (* yc (exp (- (- x xc)))))) 92 | (x1 (* 2 xc)) 93 | (y1 (gamma-integrand x1)) 94 | (y1-estimated (tail-integrand x1))) 95 | (if (<= (abs (- y1 y1-estimated)) e/100) 96 | (+ (integrate-adaptive-simpson 97 | gamma-integrand 98 | 0 xc e/100) 99 | yc) 100 | (loop x1 y1))))))) 101 | } 102 | 103 | \n We can now write a more general procedure \q{gamma} 104 | that returns $\Gamma(n)$ for any real $n$: 105 | 106 | \scmdribble{ 107 | (define gamma 108 | (lambda (n e) 109 | (cond ((< n 1) (/ (gamma (+ n 1) e) n)) 110 | ((= n 1) 1) 111 | ((< 1 n 2) (gamma-1-to-2 n e)) 112 | (else (let ((n-1 (- n 1))) 113 | (* n-1 (gamma n-1 e))))))) 114 | } 115 | 116 | \n 117 | Let us now calculate $\Gamma(3/2)$. 118 | 119 | \q{ 120 | (gamma 3/2 .001) 121 | (* 1/2 (sqrt *pi*)) 122 | } 123 | 124 | \n The second value is the analytically correct answer. 125 | (This is because $\Gamma(3/2) = 126 | (1/2)\Gamma(1/2)$, and $\Gamma(1/2)$ is known to be 127 | \ifx\shipout\UNDEFINED 128 | $\pi^{1/2}$\else 129 | $\sqrt{\pi}$\fi.) 130 | You can modify \q{gamma}’s second 131 | argument (the tolerance) to get as close an 132 | approximation as you desire. 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /mulinh.tex: -------------------------------------------------------------------------------- 1 | \scmfilename obj3.scm 2 | 3 | \scmwrite{ 4 | (load-relative "obj2.scm") 5 | (load-relative "appendmap.scm") 6 | } 7 | 8 | \index{inheritance!multiple} 9 | \index{multiple inheritance} 10 | 11 | \section{Multiple inheritance} 12 | 13 | It is easy to modify the object system to allow classes 14 | to have more than one superclass. We redefine the 15 | \q{standard-class} to have a slot called 16 | \q{class-precedence-list} instead of \q{superclass}. 17 | The \q{class-precedence-list} of a class is the list of 18 | {\em all} its superclasses, not just the {\em direct} 19 | superclasses specified during the creation of the class 20 | with \q{create-class}. The name implies that the 21 | superclasses are listed in a particular order, where 22 | superclasses occurring toward the front of the list 23 | have precedence over the ones in the back of the list. 24 | 25 | \scmdribble{ 26 | (define standard-class 27 | (vector 'value-of-standard-class-goes-here 28 | (list 'slots 'class-precedence-list 'method-names 'method-vector) 29 | '() 30 | '(make-instance) 31 | (vector make-instance))) 32 | } 33 | 34 | \scmwrite{ 35 | (vector-set! standard-class 0 standard-class) 36 | } 37 | 38 | \n Not only has the list of slots changed to include 39 | the new slot, but the erstwhile \q{superclass} slot is 40 | now \q{()} instead of \q{#t}. This is because the 41 | \q{class-precedence-list} of \q{standard-class} must be 42 | a list. We could have had its value be \q{(#t)}, but 43 | we will not mention the zero class since it is in every 44 | class’s \q{class-precedence-list}. 45 | 46 | The \q{create-class} macro has to modified to accept 47 | a list of direct superclasses instead of a solitary superclass: 48 | 49 | \scmdribble{ 50 | (define-macro create-class 51 | (lambda (direct-superclasses slots . methods) 52 | `(create-class-proc 53 | (list ,@(map (lambda (su) `,su) direct-superclasses)) 54 | (list ,@(map (lambda (slot) `',slot) slots)) 55 | (list ,@(map (lambda (method) `',(car method)) methods)) 56 | (vector ,@(map (lambda (method) `,(cadr method)) methods)) 57 | ))) 58 | } 59 | 60 | The \q{create-class-proc} must calculate the class precedence list from 61 | the supplied direct superclasses, and the slot list from the 62 | class precedence list: 63 | 64 | \scmdribble{ 65 | (define create-class-proc 66 | (lambda (direct-superclasses slots method-names method-vector) 67 | (let ((class-precedence-list 68 | (delete-duplicates 69 | (append-map 70 | (lambda (c) (vector-ref c 2)) 71 | direct-superclasses)))) 72 | (send 'make-instance standard-class 73 | 'class-precedence-list class-precedence-list 74 | 'slots 75 | (delete-duplicates 76 | (append slots (append-map 77 | (lambda (c) (vector-ref c 1)) 78 | class-precedence-list))) 79 | 'method-names method-names 80 | 'method-vector method-vector)))) 81 | } 82 | 83 | \n The procedure \q{append-map} is a composition of 84 | \q{append} and \q{map}: 85 | 86 | \q{ 87 | (define append-map 88 | (lambda (f s) 89 | (let loop ((s s)) 90 | (if (null? s) '() 91 | (append (f (car s)) 92 | (loop (cdr s))))))) 93 | } 94 | 95 | The procedure \q{send} has to search through the class precedence list 96 | left to right when it hunts for a method. 97 | 98 | \scmdribble{ 99 | (define send 100 | (lambda (method-name instance . args) 101 | (let ((proc 102 | (let ((class (class-of instance))) 103 | (if (eqv? class #t) (error 'send) 104 | (let loop ((class class) 105 | (superclasses (vector-ref class 2))) 106 | (let ((k (list-position 107 | method-name 108 | (vector-ref class 3)))) 109 | (cond (k (vector-ref 110 | (vector-ref class 4) k)) 111 | ((null? superclasses) (error 'send)) 112 | (else (loop (car superclasses) 113 | (cdr superclasses)))) 114 | )))))) 115 | (apply proc instance args)))) 116 | } 117 | 118 | \scmfilename appendmap.scm 119 | 120 | \scmwrite{ 121 | (define append-map 122 | (lambda (f s) 123 | (let loop ((s s)) 124 | (if (null? s) '() 125 | (append (f (car s)) 126 | (loop (cdr s))))))) 127 | } 128 | 129 | \scmfilename bike3.scm 130 | 131 | \scmwrite{ 132 | (define bike-class 133 | (create-class 134 | () 135 | (frame size parts chain tires) 136 | (check-fit (lambda (me inseam) 137 | (let ((bike-size (slot-value me 'size)) 138 | (ideal-size (* inseam 3/5))) 139 | (let ((diff (- bike-size ideal-size))) 140 | (cond ((<= -1 diff 1) 'perfect-fit) 141 | ((<= -2 diff 2) 'fits-well) 142 | ((< diff -2) 'too-small) 143 | ((> diff 2) 'too-big)))))))) 144 | 145 | (define my-bike 146 | (make-instance bike-class 147 | 'frame 'titanium 148 | 'size 21 149 | 'parts 'ultegra 150 | 'chain 'sachs 151 | 'tires 'continental)) 152 | } 153 | -------------------------------------------------------------------------------- /hello.tex: -------------------------------------------------------------------------------- 1 | \chapter{Enter Scheme} 2 | \label{hello} 3 | 4 | \index{begin@\q{begin}} 5 | \index{display@\q{display}} 6 | \index{newline@\q{newline}} 7 | The canonical first program is the one that says 8 | \q{"Hello, World!"} on the console. Using your 9 | favorite editor, create a file called 10 | \p{hello.scm} with the following contents: 11 | 12 | \q{ 13 | ;The first program 14 | 15 | (begin 16 | (display "Hello, World!") 17 | (newline)) 18 | } 19 | 20 | \n 21 | \index{comment} 22 | The first line is a comment. When Scheme sees a 23 | semicolon, it ignores it and all the following text on 24 | the line. 25 | 26 | \index{form} 27 | \index{subform} 28 | \index{console} 29 | \index{standard output} 30 | 31 | The \q{begin}-{\em form} is Scheme’s way of 32 | introducing a sequence of {\em subforms}. In this 33 | case there are two subforms. The first is a call to 34 | the 35 | \q{display} procedure that outputs its argument 36 | (the string \q{"Hello, World!"}) to the console (or 37 | “standard output”). It is followed by a \q{newline} 38 | procedure call, which outputs a carriage return. 39 | 40 | \index{command line} 41 | \index{MzScheme} 42 | 43 | To run this program, first start your Scheme. This is 44 | usually done by typing the name of your Scheme 45 | executable at the operating-system command line. 46 | E.g., in the case of MzScheme \cite{mzscheme}, 47 | you type 48 | 49 | \p{ 50 | mzscheme 51 | } 52 | 53 | \n at the operating-system prompt. 54 | 55 | \index{listener} 56 | \index{read-eval-print loop} 57 | \index{evaluation} 58 | 59 | This invokes the Scheme {\em listener}, which {\em read}s 60 | your input, {\em eval}uates it, {\em print}s the result (if 61 | any), and then waits for more input from you. For this 62 | reason, it is often called the {\em read-eval-print loop}. 63 | Note that this is not much different from your 64 | operating-system command line, which also reads your 65 | commands, executes them, and then waits for more. Like the 66 | operating system, the Scheme listener has its own prompt — 67 | usually this is 68 | \p{>}, but could be something else. 69 | 70 | \index{load@\q{load}} 71 | 72 | At the listener prompt, {\em load} the file 73 | \p{hello.scm}. This is done by typing 74 | 75 | \q{ 76 | (load "hello.scm") 77 | } 78 | 79 | \n Scheme will now execute the contents of 80 | \p{hello.scm}, outputting \p{Hello, World!} followed 81 | by a carriage return. After this, you will get the listener 82 | prompt again, waiting for more input from you. 83 | 84 | Since you have such an eager listener, you need not 85 | always write your programs in a file and load them. 86 | Sometimes, it is easier, especially when you are in an 87 | exploring mood, to simply type expressions directly at 88 | the listener prompt and see what happens. For example, 89 | typing the form 90 | 91 | \q{ 92 | (begin (display "Hello, World!") 93 | (newline)) 94 | } 95 | 96 | \n at the Scheme prompt produces 97 | 98 | \p{ 99 | Hello, World! 100 | } 101 | 102 | Actually, you could simply have typed the form 103 | \q{"Hello, World!"} at the listener, and you would have 104 | obtained as result the string 105 | 106 | \q{ 107 | "Hello, World!" 108 | } 109 | 110 | \n because that is the result of the listener evaluating 111 | \q{"Hello, World!"}. 112 | 113 | Other than the fact that the second approach produces a 114 | result with double-quotes around it, there is one other 115 | significant difference between the last two programs. 116 | The first (i.e., the one with the \q{begin}) does not evaluate 117 | to anything — the \p{Hello, World!} it emits is a 118 | {\em side-effect} produced by the \q{display} and 119 | \q{newline} procedures writing to the standard output. 120 | In the second program, the form 121 | \q{"Hello, World!"} {\em evaluates} to the result, which 122 | in this case is the same string as the form. 123 | 124 | Henceforth, we will use the notation \q{|evalsto} to denote 125 | evaluation. Thus 126 | 127 | \q{ 128 | E |evalsto v 129 | } 130 | 131 | \n indicates that the form \q{E} evaluates to a result value 132 | of \q{v}. E.g., 133 | 134 | \q{ 135 | (begin 136 | (display "Hello, World!") 137 | (newline)) 138 | |evalsto 139 | } 140 | 141 | \n (i.e., nothing or void), although it has the side-effect of writing 142 | 143 | \p{ 144 | Hello, World! 145 | } 146 | 147 | \n to the standard output. 148 | On the other hand, 149 | 150 | \q{ 151 | "Hello, World!" 152 | |evalsto "Hello, World!" 153 | } 154 | 155 | \n In either case, we are still at the listener. To exit, 156 | type 157 | 158 | \index{exit@\q{exit}} 159 | \q{ 160 | (exit) 161 | } 162 | 163 | \n and this will land you back at the operating-system 164 | command-line (which, as we’ve seen, is also a kind of 165 | listener). 166 | 167 | The listener is convenient for interactive testing of 168 | programs and program fragments. However it is by no 169 | means necessary. You may certainly stick to the 170 | tradition of creating programs in their entirety in 171 | files, and having Scheme execute them without any 172 | explicit “listening”. In MzScheme, for instance, you 173 | could say (at the operating-system prompt) 174 | 175 | \p{ 176 | mzscheme -r hello.scm 177 | } 178 | 179 | \n and this will produce the greeting without making you 180 | deal with 181 | the listener. After the greeting, \p{mzscheme} will 182 | return you to the 183 | operating-system prompt. This is almost as if you said 184 | 185 | \p{ 186 | echo Hello, World! 187 | } 188 | 189 | You could even make \p{hello.scm} seem like an 190 | operating-system command (a shell script or a 191 | batch file), but that will have to wait till 192 | chapter~\ref{script}. 193 | 194 | \endinput 195 | 196 | One way to do this in the Unix version of 197 | MzScheme is to place the following line at the head of 198 | \p{hello.scm}: 199 | 200 | \q{ 201 | ":";exec mzscheme -r $0 $* 202 | } 203 | 204 | \n (This assumes your Unix command shell is either the 205 | Bourne shell or \p{bash}.) 206 | 207 | Make the file executable by doing \p{chmod +x 208 | hello.scm}, and then simply type 209 | 210 | \p{ 211 | hello.scm 212 | } 213 | 214 | \n at the Unix prompt. 215 | -------------------------------------------------------------------------------- /form.tex: -------------------------------------------------------------------------------- 1 | \chapter{Forms} 2 | 3 | The reader will have noted that the Scheme example 4 | programs provided thus far are also s-expressions. 5 | This is true of all Scheme programs: Programs are data. 6 | 7 | Thus, the character datum \q{#\c} is a program, or a 8 | {\em form}. We will use the more general term {\em 9 | form} instead of {\em program}, so that we can deal 10 | with program fragments too. 11 | 12 | Scheme evaluates the form \q{#\c} to the value \q{#\c}, 13 | because \q{#\c} is self-evaluating. Not all 14 | s-expressions are self-evaluating. For instance the 15 | symbol s-expression 16 | \q{xyz} evaluates to the value held by the {\em variable} 17 | \q{xyz}. The list s-expression 18 | \q{(string->number "16")} 19 | evaluates to the number 16. 20 | 21 | Not all s-expressions are valid programs. If you typed 22 | the dotted-pair s-expression \q{(1 . 2)} at the Scheme 23 | listener, you will get an error. 24 | 25 | Scheme evaluates a list form by examining the first 26 | element, or {\em head}, of the form. If the head 27 | evaluates to a procedure, the rest of the form is 28 | evaluated to get the procedure’s arguments, and the 29 | procedure is {\em applied} to the arguments. 30 | 31 | If the head of the form is a {\em special form}, the 32 | evaluation proceeds in a manner idiosyncratic to that 33 | form. Some special forms we have already seen 34 | are \q{begin}, \q{define}, and \q{set!}. \q{begin} causes its 35 | subforms to be evaluated in order, the result of the 36 | entire form being the result of the last subform. 37 | \q{define} introduces and initializes a variable. 38 | \q{set!} changes the binding of a variable. 39 | 40 | \index{procedure} 41 | \index{lambda@\q{lambda}} 42 | \section{Procedures} 43 | 44 | We have seen quite a few primitive Scheme procedures, 45 | e.g., \q{cons}, \q{string->list}, and the like. Users 46 | can create their own procedures using the special form 47 | \q{lambda}. For example, the following defines a 48 | procedure that adds \q{2} to its argument: 49 | 50 | \q{ 51 | (lambda (x) (+ x 2)) 52 | } 53 | 54 | The first subform, \q{(x)}, is the list of parameters. 55 | The remaining subform(s) constitute the procedure’s 56 | body. This procedure can be called on an argument, 57 | just like a primitive procedure: 58 | 59 | \q{ 60 | ((lambda (x) (+ x 2)) 5) 61 | |evalsto 7 62 | } 63 | 64 | If we wanted to call this same procedure many times, we 65 | could create a replica using \q{lambda} each time, but 66 | we can do better. We can use a variable to hold the 67 | procedure value: 68 | 69 | \q{ 70 | (define add2 71 | (lambda (x) (+ x 2))) 72 | } 73 | 74 | We can then use the variable \q{add2} each time we need 75 | a procedure for adding \q{2} to its argument: 76 | 77 | \q{ 78 | (add2 4) |evalsto 6 79 | (add2 9) |evalsto 11 80 | } 81 | 82 | \index{procedure!parameters} 83 | \subsection{Procedure parameters} 84 | 85 | The parameters of a \q{lambda}-procedure are specified 86 | by its first subform (the form immediately following 87 | the head, the symbol \q{lambda}). \q{add2} 88 | is a single-argument — or {\em unary} — procedure, and so its parameter 89 | list is the singleton list \q{(x)}. The symbol \q{x} 90 | acts as a variable holding the procedure’s argument. 91 | Each occurrence of \q{x} in the procedure’s body refers 92 | to the procedure’s argument. The variable \q{x} is 93 | said to be {\em local} to the procedure’s body. 94 | 95 | We can use 2-element lists for 2-argument procedures, 96 | and in general, {\em n}-element lists for {\em 97 | n}-argument procedures. The following is a 2-argument 98 | procedure that calculates the area of a rectangle. Its 99 | two arguments are the length and breadth of the 100 | rectangle. 101 | 102 | \q{ 103 | (define area 104 | (lambda (length breadth) 105 | (* length breadth))) 106 | } 107 | 108 | Notice that \q{area} multiplies its arguments, and so 109 | does the primitive procedure \q{*}. We could have 110 | simply said: 111 | 112 | \q{ 113 | (define area *) 114 | } 115 | 116 | \subsection{Variable number of arguments} 117 | 118 | Some procedures can be called at different times with 119 | different numbers of arguments. To do this, the 120 | \q{lambda} parameter list is replaced by a single 121 | symbol. This symbol acts as a variable that is bound 122 | to the list of the arguments that the procedure is 123 | called on. 124 | 125 | In general, the \q{lambda} parameter list can be a list 126 | of the form \q{(x ...)}, a symbol, or a dotted pair of 127 | the form \q{(x ... . z)}. In the dotted-pair case, all 128 | the variables before the dot are bound to the 129 | corresponding arguments in the procedure call, with the 130 | single variable after the dot picking up all the 131 | remaining arguments as one list. 132 | 133 | %examples 134 | \index{apply@\q{apply}} 135 | 136 | \section{\q{apply}} 137 | 138 | The Scheme procedure \q{apply} lets us call a procedure 139 | on a {\em list} of its arguments. 140 | 141 | \q{ 142 | (define x '(1 2 3)) 143 | 144 | (apply + x) 145 | |evalsto 6 146 | } 147 | 148 | In general, \q{apply} takes a procedure, followed by a 149 | variable number of other arguments, the last of which 150 | must be a list. It constructs the argument list by 151 | prefixing the last argument with all the other 152 | (intervening) arguments. It then returns the result of 153 | calling the procedure 154 | on this argument list. E.g., 155 | 156 | \q{ 157 | (apply + 1 2 3 x) 158 | |evalsto 12 159 | } 160 | 161 | \index{begin@\q{begin}} 162 | 163 | \section{Sequencing} 164 | 165 | We used the \q{begin} special form to bunch together a 166 | group of subforms that need to be evaluated in 167 | sequence. Many Scheme forms have {\em implicit} 168 | \q{begin}s. For example, let’s define a 3-argument procedure that 169 | displays its three arguments, with spaces between 170 | them. A possible definition is: 171 | 172 | \q{ 173 | (define display3 174 | (lambda (arg1 arg2 arg3) 175 | (begin 176 | (display arg1) 177 | (display " ") 178 | (display arg2) 179 | (display " ") 180 | (display arg3) 181 | (newline)))) 182 | } 183 | 184 | \index{begin@\q{begin}!implicit} 185 | 186 | In Scheme, \q{lambda}-bodies are implicit \q{begin}s. 187 | Thus, the \q{begin} in \q{display3}’s body isn’t needed, although it doesn’t 188 | hurt. \q{display3}, more simply, is: 189 | 190 | \q{ 191 | (define display3 192 | (lambda (arg1 arg2 arg3) 193 | (display arg1) 194 | (display " ") 195 | (display arg2) 196 | (display " ") 197 | (display arg3) 198 | (newline))) 199 | } 200 | -------------------------------------------------------------------------------- /clock.tex: -------------------------------------------------------------------------------- 1 | \chapter{A clock for infinity} 2 | \label{clock} 3 | 4 | \index{clock!Guile} 5 | \index{Guile!clock} 6 | The Guile \cite{guile} procedure \q{alarm} provides an interruptable 7 | timer mechanism. The user can set or reset the alarm 8 | for some time units, or stop it. When the alarm’s 9 | timer runs out of this time, it will set off an alarm, 10 | whose consequences are user-settable. Guile’s 11 | \q{alarm} is not quite the clock of 12 | sec \ref{engine-clock}, but we can modify it easily 13 | enough. 14 | 15 | The alarm’s timer is initially {\em stopped} or {\em 16 | quiescent}, i.e., it will not set off an alarm even as 17 | time goes by. To set the alarm’s time-to-alarm to be 18 | \q{n} seconds, where \q{n} is not \q{0}, run \q{(alarm 19 | n)}. If the timer was already set (but has not yet set 20 | off an alarm), the \q{(alarm n)} procedure call will 21 | return the number of seconds remaining from the 22 | previous alarm setting. If there is no previous alarm 23 | setting, \q{(alarm n)} returns \q{0}. 24 | 25 | The procedure call \q{(alarm 0)} {\em stops} the 26 | alarm’s timer, i.e., the countdown of time is stopped, 27 | the timer becomes quiescent and no alarm will go off. 28 | \q{(alarm 0)} also returns the seconds remaining from a 29 | previous alarm setting, if any. 30 | 31 | By default, when the alarm’s countdown reaches 0, 32 | Guile will display a message on the console and exit. 33 | More useful behavior can be obtained by 34 | using the procedure 35 | \q{sigaction}, as follows: 36 | 37 | \q{ 38 | (sigaction SIGALRM 39 | (lambda (sig) 40 | (display "Signal ") 41 | (display sig) 42 | (display " raised. Continuing...") 43 | (newline))) 44 | } 45 | 46 | \n 47 | The first argument \q{SIGALRM} (which happens to be 48 | \q{14}) identifies to \q{sigaction} that it is the 49 | alarm handler that needs setting.\f{There are other 50 | signals with their corresponding handlers, and 51 | \q{sigaction} can be used to set these as well.} The 52 | second argument is a unary alarm-handling procedure of 53 | the user’s choice. In this example, when the alarm 54 | goes off, the handler displays \q{"Signal 14 raised. 55 | Continuing..."} on the console without exiting Scheme. 56 | (The \q{14} is the \q{SIGALRM} value that the alarm 57 | will pass to its handler. Don’t worry about it now.) 58 | 59 | From our point of view, this simple timer mechanism 60 | poses one problem. A return value of \q{0} from a call 61 | to the procedure \q{alarm} is ambiguous: It could 62 | either mean that the alarm was quiescent, or that 63 | it was just about to run out of time. We could resolve 64 | this ambiguity if we could include “\q{*infinity*}” 65 | in the alarm arithmetic. In other words, we would like 66 | a {\em clock} that works almost like \q{alarm}, 67 | except that a quiescent clock is one with 68 | \q{*infinity*} seconds. This will make many things 69 | natural, viz., 70 | 71 | (1) \q{(clock n)} on a quiescent clock returns 72 | \q{*infinity*}, not \q{0}. 73 | 74 | (2) To stop the clock, call \q{(clock *infinity*)}, 75 | {\em not} \q{(clock 0)}. 76 | 77 | (3) \q{(clock 0)} is equivalent to setting the clock to 78 | an infinitesimally small amount of time, viz., to cause 79 | it to raise an alarm instantaneously. 80 | 81 | In Guile, we can define \q{*infinity*} as the following 82 | “number”: 83 | 84 | \scmfilename guile-clock.scm 85 | \scmdribble{ 86 | (define *infinity* (/ 1 0)) 87 | } 88 | 89 | We can define \q{clock} in terms of \q{alarm}. 90 | 91 | \scmdribble{ 92 | (define clock 93 | (let ((stopped? #t) 94 | (clock-interrupt-handler 95 | (lambda () (error "Clock interrupt!")))) 96 | (let ((generate-clock-interrupt 97 | (lambda () 98 | (set! stopped? #t) 99 | (clock-interrupt-handler)))) 100 | (sigaction SIGALRM 101 | (lambda (sig) (generate-clock-interrupt))) 102 | (lambda (msg val) 103 | (case msg 104 | ((set-handler) 105 | (set! clock-interrupt-handler val)) 106 | ((set) 107 | (cond ((= val *infinity*) 108 | ;This is equivalent to stopping the clock. 109 | ;This is almost equivalent to (alarm 0), except 110 | ;that if the clock is already stopped, 111 | ;return *infinity*. 112 | 113 | (let ((time-remaining (alarm 0))) 114 | (if stopped? *infinity* 115 | (begin (set! stopped? #t) 116 | time-remaining)))) 117 | 118 | ((= val 0) 119 | ;This is equivalent to setting the alarm to 120 | ;go off immediately. This is almost equivalent 121 | ;to (alarm 0), except you force the alarm 122 | ;handler to run. 123 | 124 | (let ((time-remaining (alarm 0))) 125 | (if stopped? 126 | (begin (generate-clock-interrupt) 127 | *infinity*) 128 | (begin (generate-clock-interrupt) 129 | time-remaining)))) 130 | 131 | (else 132 | ;This is equivalent to (alarm n) for n != 0. 133 | ;Just remember to return *infinity* if the 134 | ;clock was previously quiescent. 135 | 136 | (let ((time-remaining (alarm val))) 137 | (if stopped? 138 | (begin (set! stopped? #f) *infinity*) 139 | time-remaining)))))))))) 140 | } 141 | 142 | \n 143 | The \q{clock} procedure uses three internal state 144 | variables: 145 | 146 | (1) \q{stopped?}, to describe if the clock is stopped; 147 | 148 | (2) \q{clock-interrupt-handler}, which is a thunk 149 | describing the user-specified part of the 150 | alarm-handling action; and 151 | 152 | (3) \q{generate-clock-interrupt}, another thunk which 153 | will set \q{stopped?} to false before running the 154 | user-specified alarm handler. 155 | 156 | The \q{clock} procedure takes two arguments. If the 157 | first argument is \q{set-handler}, it uses the second 158 | argument as the alarm handler. 159 | 160 | If the first argument is \q{set}, it sets the 161 | time-to-alarm to the second argument, returning the 162 | time remaining from a previous setting. The code 163 | treats \q{0}, \q{*infinity*} and other values for time 164 | differently so that the user gets a mathematically 165 | transparent interface to \q{alarm}. 166 | 167 | \scmwrite{ 168 | (define clock-min min) 169 | (define clock-minus -) 170 | (define clock-plus +) 171 | } 172 | -------------------------------------------------------------------------------- /struct.tex: -------------------------------------------------------------------------------- 1 | \chapter{Structures} 2 | 3 | \index{structure} 4 | Data that are naturally grouped are called {\em 5 | structures}. One can use Scheme’s compound data types, 6 | e.g., vectors or lists, to represent structures. E.g., 7 | let’s say we are dealing with grouped data relevant to 8 | a (botanical) {\em tree}. The individual elements of 9 | the data, or {\em fields}, could be: {\em height}, {\em 10 | girth}, {\em age}, {\em leaf-shape}, and {\em 11 | leaf-color}, making a total of 5 fields. Such data 12 | could be represented as a 5-element vector. The fields 13 | could be accessed using 14 | \q{vector-ref} and modified using \q{vector-set!}. 15 | Nevertheless, we wouldn’t want to be saddled with the 16 | burden of remembering which vector index corresponds to 17 | which field. That would be a thankless and error-prone 18 | activity, especially if fields get excluded or included 19 | over the course of time. 20 | 21 | \index{defstruct@\q{defstruct}} 22 | \index{structure!defstruct@\q{defstruct}} 23 | 24 | We will therefore use a Scheme macro \q{defstruct} to 25 | define a structure data type, which is basically a 26 | vector, but which comes with an appropriate suite of 27 | procedures for creating instances of the structure, and 28 | for accessing and modifying its fields. Thus, our \q{tree} 29 | structure could be defined as: 30 | 31 | \q{ 32 | (defstruct tree height girth age leaf-shape leaf-color) 33 | } 34 | 35 | This gives us a constructor procedure named 36 | \q{make-tree}; accessor procedures for each field, 37 | named 38 | \q{tree.height}, \q{tree.girth}, etc; and modifier 39 | procedures for each field, named \q{set!tree.height}, 40 | \q{set!tree.girth}, etc. The constructor is used as 41 | follows: 42 | 43 | \q{ 44 | (define coconut 45 | (make-tree 'height 30 46 | 'leaf-shape 'frond 47 | 'age 5)) 48 | } 49 | 50 | \n The constructor’s arguments are in the form of 51 | twosomes, a field name followed by its initialization. 52 | The fields can occur in any order, and may even be 53 | missing, in which case their value is undefined. 54 | 55 | The accessor procedures are invoked as follows: 56 | 57 | \q{ 58 | (tree.height coconut) |evalsto 30 59 | (tree.leaf-shape coconut) |evalsto frond 60 | (tree.girth coconut) |evalsto 61 | } 62 | 63 | \n The \q{tree.girth} accessor returns an undefined value, 64 | because we did not specify \q{girth} for the 65 | \q{coconut} \q{tree}. 66 | 67 | The modifier procedures are invoked as follows: 68 | 69 | \q{ 70 | (set!tree.height coconut 40) 71 | (set!tree.girth coconut 10) 72 | } 73 | 74 | If we now access these fields using the corresponding 75 | accessors, we will get the new values: 76 | 77 | \q{ 78 | (tree.height coconut) |evalsto 40 79 | (tree.girth coconut) |evalsto 10 80 | } 81 | 82 | \section{Default initializations} 83 | 84 | We can have some initializations done during the 85 | definition of the structure itself, instead of per 86 | instance. Thus, we could postulate that \q{leaf-shape} 87 | and \q{leaf-color} are by default \q{frond} and 88 | \q{green} respectively. We can always override these 89 | defaults by providing explicit initialization in the 90 | \q{make-tree} call, or by 91 | using a field modifier after the structure instance has 92 | been created: 93 | 94 | \q{ 95 | (defstruct tree height girth age 96 | (leaf-shape 'frond) 97 | (leaf-color 'green)) 98 | 99 | (define palm (make-tree 'height 60)) 100 | 101 | (tree.height palm) 102 | |evalsto 60 103 | 104 | (tree.leaf-shape palm) 105 | |evalsto frond 106 | 107 | (define plantain 108 | (make-tree 'height 7 109 | 'leaf-shape 'sheet)) 110 | 111 | (tree.height plantain) 112 | |evalsto 7 113 | 114 | (tree.leaf-shape plantain) 115 | |evalsto sheet 116 | 117 | (tree.leaf-color plantain) 118 | |evalsto green 119 | } 120 | 121 | \section{\q{defstruct} defined} 122 | 123 | The \q{defstruct} macro definition follows: 124 | 125 | \scmfilename defstruct.scm 126 | 127 | \scmwrite& 128 | ;(defstruct structname [field | (field default-value)] ...) 129 | ; 130 | ;creates 131 | ;the constructor make-structname 132 | ;the predicate structname? 133 | ;the accessors structname.field (for each field) 134 | ;the setters set!structname.field (for each field) 135 | ; 136 | ;make-structname can take {field init-value} arguments, 137 | ;in which it case it sets field to init-value. Otherwise, 138 | ;it sets field to default-value, if such was provided in 139 | ;the defstruct call 140 | 141 | (load-relative "listpos.scm") 142 | & 143 | 144 | \scmdribble{ 145 | (define-macro defstruct 146 | (lambda (s . ff) 147 | (let ((s-s (symbol->string s)) (n (length ff))) 148 | (let* ((n+1 (+ n 1)) 149 | (vv (make-vector n+1))) 150 | (let loop ((i 1) (ff ff)) 151 | (if (<= i n) 152 | (let ((f (car ff))) 153 | (vector-set! vv i 154 | (if (pair? f) (cadr f) '(if #f #f))) 155 | (loop (+ i 1) (cdr ff))))) 156 | (let ((ff (map (lambda (f) (if (pair? f) (car f) f)) 157 | ff))) 158 | `(begin 159 | (define ,(string->symbol 160 | (string-append "make-" s-s)) 161 | (lambda fvfv 162 | (let ((st (make-vector ,n+1)) (ff ',ff)) 163 | (vector-set! st 0 ',s) 164 | ,@(let loop ((i 1) (r '())) 165 | (if (>= i n+1) r 166 | (loop (+ i 1) 167 | (cons `(vector-set! st ,i 168 | ,(vector-ref vv i)) 169 | r)))) 170 | (let loop ((fvfv fvfv)) 171 | (if (not (null? fvfv)) 172 | (begin 173 | (vector-set! st 174 | (+ (list-position (car fvfv) ff) 175 | 1) 176 | (cadr fvfv)) 177 | (loop (cddr fvfv))))) 178 | st))) 179 | ,@(let loop ((i 1) (procs '())) 180 | (if (>= i n+1) procs 181 | (loop (+ i 1) 182 | (let ((f (symbol->string 183 | (list-ref ff (- i 1))))) 184 | (cons 185 | `(define ,(string->symbol 186 | (string-append 187 | s-s "." f)) 188 | (lambda (x) (vector-ref x ,i))) 189 | (cons 190 | `(define ,(string->symbol 191 | (string-append 192 | "set!" s-s "." f)) 193 | (lambda (x v) 194 | (vector-set! x ,i v))) 195 | procs)))))) 196 | (define ,(string->symbol (string-append s-s "?")) 197 | (lambda (x) 198 | (and (vector? x) 199 | (eqv? (vector-ref x 0) ',s)))))))))) 200 | } 201 | 202 | -------------------------------------------------------------------------------- /tyscheme.bib: -------------------------------------------------------------------------------- 1 | % last modified 2020-11-13 2 | 3 | @book{sicp, 4 | author = "Harold Abelson and Gerald Jay {Sussman with Julie Sussman}", 5 | title = "\urlp{Structure and Interpretation of Computer Programs 6 | (``SICP'')}{http://mitpress.mit.edu/sicp/full-text/book/book.html}", 7 | edition = "2nd", 8 | publisher = "MIT Press", 9 | year = 1996, 10 | } 11 | 12 | @book{htdp, 13 | author = "Matthias Felleisen and Robert Bruce Findler and Matthew Flatt 14 | and Shriram Krishnamurthi", 15 | title = "\urlp{How to Design Programs: An Introduction to Programming 16 | and Computing}{http://www.htdp.org}", 17 | publisher = "MIT Press", 18 | year = 2001, 19 | } 20 | 21 | @book{tspl, 22 | author = "R. Kent Dybvig", 23 | title = "\urlp{The Scheme Programming 24 | Language}{http://www.scheme.com/tspl2d}", 25 | edition = "2nd", 26 | publisher = "Prentice Hall PTR", 27 | year = 1996, 28 | } 29 | 30 | @book{hunter, 31 | author = "J. A. H. Hunter", 32 | title = "\urlh{http://store.yahoo.com/doverpublications/0486233472.html}{Mathematical 33 | Brain-Teasers}", 34 | publisher = "Dover Publications", 35 | year = 1976, 36 | } 37 | 38 | @book{4cp, 39 | author = "Thomas L. Saaty and Paul C. Kainen", 40 | title = "The Four-Color Problem: Assaults and Conquest", 41 | publisher = "Dover Publications", 42 | year = 1986, 43 | } 44 | 45 | @book{aop, 46 | author = "Leon Sterling and Ehud Shapiro", 47 | title = "\urlh{http://mitpress.mit.edu/book-home.tcl?isbn=0262193388}{The 48 | Art of Prolog}", 49 | publisher = "MIT Press", 50 | year = 1994, 51 | edition = "2nd", 52 | } 53 | 54 | @book{tls, 55 | author = "Daniel P. Friedman and Matthias Felleisen", 56 | title = "\urlh{http://www.ccs.neu.edu/~matthias/BTLS}{The Little Schemer}", 57 | publisher = "MIT Press", 58 | year = 1996, 59 | edition = "4th", 60 | } 61 | 62 | @book{tss, 63 | author = "Daniel P. Friedman and Matthias Felleisen", 64 | title = "\urlh{http://www.ccs.neu.edu/~matthias/BTSS}{The Seasoned Schemer}", 65 | publisher = "MIT Press", 66 | year = 1996, 67 | } 68 | 69 | @book{eopl, 70 | author = "Daniel P. Friedman and Mitchell Wand and Christopher T. Haynes", 71 | title = "\urlh{http://mitpress.mit.edu/book-home.tcl?isbn=0262061457}{Essentials 72 | of Programming Languages}", 73 | publisher = "MIT Press, McGraw-Hill", 74 | year = 1992, 75 | } 76 | 77 | @book{q:lisp, 78 | author = "Christian Queinnec", 79 | title = "\urlh{http://youpou.lip6.fr/queinnec/WWW/LiSP.html}{Lisp 80 | in Small Pieces}", 81 | publisher = "Cambridge University Press", 82 | year = 1996, 83 | } 84 | 85 | @book{keene, 86 | author = "Sonya E. Keene", 87 | title = "Object-oriented Programming in Common Lisp: A 88 | Programmer's Guide to CLOS", 89 | publisher = "Addison-Wesley", 90 | year = 1989, 91 | } 92 | 93 | @book{amop, 94 | author = "Gregor Kiczales and Jim des Rivi\`eres and Daniel G. Bobrow", 95 | title = "The Art of the Metaobject Protocol", 96 | publisher = "MIT Press", 97 | year = 1991, 98 | } 99 | 100 | @book{hmf, 101 | editor = "Milton Abramowitz and Irene A. Stegun", 102 | title = "\urlh{http://store.yahoo.com/doverpublications/0486612724.html}{Handbook 103 | of Mathematical Functions: with Formulas, Graphs, and Mathematical Tables}", 104 | publisher = "Dover Publications", 105 | year = 1965, 106 | } 107 | 108 | @book{nahin:dice, 109 | author = "Paul J. Nahin", 110 | title = "Digital Dice: Computational Solutions to Practical Probability Problems", 111 | publisher = "Princeton University Press", 112 | year = 2008, 113 | } 114 | 115 | @inproceedings{wc:amb, 116 | author = "William Clinger", 117 | title = "{Nondeterministic call by need is neither lazy nor 118 | by name}", 119 | booktitle = "{Proc. ACM Symp. Lisp and Functional 120 | Programming}", 121 | year = 1982, 122 | pages = "226--234", 123 | } 124 | 125 | @inproceedings{logick, 126 | author = "Christopher T. Haynes", 127 | title = "{Logic continuations}", 128 | booktitle = "{J. Logic Program.}", 129 | year = 1987, 130 | note = "vol 4", 131 | pages = "157--176", 132 | } 133 | 134 | @inproceedings{engine, 135 | author = "Christopher T. Haynes and Daniel P. Friedman", 136 | title = "{Engines Build Process Abstractions}", 137 | booktitle = "{Conf. ACM Symp. Lisp and Functional 138 | Programming}", 139 | year = 1984, 140 | pages = "18--24", 141 | } 142 | 143 | @inproceedings{coroutine, 144 | author = "Christopher T. Haynes and Daniel P. Friedman and 145 | Mitchell Wand", 146 | title = "{Continuations and Coroutines}", 147 | booktitle = "{Conf. ACM Symp. Lisp and Functional 148 | Programming}", 149 | year = 1984, 150 | pages = "293--298", 151 | } 152 | 153 | @inproceedings{jmc:amb, 154 | author = "John McCarthy", 155 | title = "\urlh{http://www-formal.stanford.edu/jmc/basis1/basis1.html}{A 156 | Basis for a Mathematical Theory of Computation}", 157 | booktitle = "{Computer Programming and Formal Systems}", 158 | editor = "P. Braffort and D. Hirschberg", 159 | publisher = "North-Holland", 160 | year = 1967, 161 | } 162 | 163 | @inproceedings{zmc:amb, 164 | author = "Ramin Zabih and David McAllester and David Chapman", 165 | title = "{Non-deterministic Lisp with dependency-directed 166 | backtracking}", 167 | booktitle = "{AAAI-87}", 168 | year = 1987, 169 | pages = "59--64", 170 | } 171 | 172 | @misc{cgi, 173 | author = "NCSA", 174 | title = "\urlp{The Common Gateway 175 | Interface}{http://hoohoo.ncsa.uiuc.edu/cgi}", 176 | } 177 | 178 | @misc{r5rs, 179 | author = "Richard Kelsey and William Clinger and 180 | Jonathan {Rees (eds)}", 181 | title = "\urlp{Revised\^{}5 Report on the Algorithmic Language Scheme 182 | (“R5RS”)}{http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs.html}", 183 | year = 1998, 184 | } 185 | 186 | @misc{gambit, 187 | author = "Marc Feeley", 188 | title = "\urlp{Gambit Scheme System}{http://www.iro.umontreal.ca/~gambit}", 189 | } 190 | 191 | @misc{mzscheme, 192 | author = "Matthew Flatt", 193 | title = "\urlp{MzScheme}{http://www.plt-scheme.org/software/mzscheme}", 194 | } 195 | 196 | @misc{stk, 197 | author = "Erick Gallesio", 198 | title = "\urlp{STk}{http://kaolin.unice.fr/STk/STk.html}", 199 | } 200 | 201 | @misc{guile, 202 | author = "FSF", 203 | title = "\urlp{Guile: Project GNU's Extension 204 | Language}{http://www.gnu.org/software/guile/guile.html}", 205 | } 206 | 207 | @misc{gauche, 208 | author = "Shiro Kawai", 209 | title = 210 | "\urlp{Gauche: A Scheme Implementation}{http://www.shiro.dreamhost.com/scheme/gauche/}" 211 | } 212 | 213 | @misc{chicken, 214 | author = "Felix L. Winkelmann", 215 | title = "\urlp{Chicken: A practical and portable Scheme 216 | system}{http://www.call-with-current-continuation.org/chicken.html}", 217 | } 218 | 219 | @misc{scm, 220 | author = "Aubrey Jaffer", 221 | title = "\urlp{SCM}{http://swissnet.ai.mit.edu/~jaffer/SCM.html}", 222 | } 223 | 224 | @misc{kawa, 225 | author = "Per Bothner", 226 | title = "\urlp{The Kawa Scheme system}{http://www.gnu.org/software/kawa}", 227 | } 228 | 229 | @misc{mitscheme, 230 | author = "{MIT Scheme Team}", 231 | title = "\urlp{MIT Scheme}{http://www.swiss.ai.mit.edu/projects/scheme}", 232 | } 233 | 234 | @misc{bigloo, 235 | author = "Manuel Serrano", 236 | title = "\urlp{Bigloo}{http://www-sop.inria.fr/mimosa/fp/Bigloo}", 237 | } 238 | 239 | @misc{pocketscheme, 240 | author = "Ben Goetter", 241 | title = "\urlp{Pocket Scheme for the H/PC and 242 | P/PC}{http://www.angrygraycat.com/scheme/pscheme.htm}", 243 | } 244 | 245 | @techreport{mf:prolog, 246 | author = "Matthias Felleisen", 247 | title = "{Transliterating Prolog into Scheme}", 248 | institution = "{Indiana U. Comp. Sci. Dept}", 249 | year = 1985, 250 | number = 182, 251 | } 252 | 253 | -------------------------------------------------------------------------------- /umbrella.tex: -------------------------------------------------------------------------------- 1 | \subsection{Getting wet} 2 | 3 | In the \q{same-fringe?} program, the coroutines for the two trees 4 | report back to one managing coroutine, which takes care to call 5 | them alternately, as many times as needed. The two tree 6 | coroutines don't interact with each other. Let’s now explore a 7 | scenario where all the managed coroutines can resume each other: 8 | i.e., the managing coroutine is hands-off and doesn't micromanage 9 | the dispatching at all, simply reporting the final result when 10 | the work is done. 11 | 12 | An absent-minded Professor F~\cite{nahin:dice} wants to conserve 13 | fossil fuel and get some exercise in the bargain. He decides to 14 | walk to work in the morning and back home in the evening, and he 15 | plans to stick to this routine for five years. The walk is short 16 | enough that if the weather is clear when he sets out he will make 17 | it to his destination without threat of rain. But if it is 18 | raining, which it can be with a certain probability 19 | \q{*rain-prob*}, he can’t go out without an umbrella. 20 | 21 | \scmfilename umbrella.scm 22 | 23 | \scmdribble{ 24 | (define *rain-prob* 0.4) 25 | (define *max-num-walks* (* 365 2 5)) ;2 walks/day for 5 years 26 | } 27 | 28 | \n To prepare for this, Prof F decides to keep an umbrella at 29 | both home and office. Unfortunately, the smart prof is also 30 | absent-minded, so if the weather is clear, he invariably neglects 31 | to take an umbrella along, so there is a possibility that when it 32 | does rain, both his umbrellas are at the other place and he is 33 | stranded. How many walks can he hope to make before being 34 | stranded? 35 | 36 | We can model each location (home, office) as a coroutine that 37 | keeps track of the number of umbrellas it has. Each walk is 38 | simulated by one location resuming the other. The resumption's 39 | arguments include whether Prof F is carrying an umbrella (i.e., 40 | it is raining) and the number of walks so far (including the 41 | current one). When Prof F gets stranded, one of the location 42 | coroutines resumes the manager coroutine with the number of walks 43 | achieved. 44 | 45 | The two location coroutines are just two instances of the same 46 | kind, and as such can be generated by a single procedure. We will 47 | have this procedure take the other location and the walk-manager 48 | as parameters. 49 | 50 | \scmdribble{ 51 | (define make-location-cor 52 | (lambda (other-location-cor manager-cor) 53 | (coroutine v 54 | (let ((num-umbrellas 1)) 55 | (let loop ((umbrella? (car v)) 56 | (walks-so-far (cadr v))) 57 | (when umbrella? 58 | (set! num-umbrellas (+ num-umbrellas 1))) 59 | (cond ((>= walks-so-far *max-num-walks*) 60 | (resume manager-cor walks-so-far)) 61 | ((< (random) *rain-prob*) 62 | (cond ((> num-umbrellas 0) 63 | (set! num-umbrellas 64 | (- num-umbrellas 1)) 65 | (apply loop 66 | (resume other-location-cor 67 | (list #t 68 | (+ walks-so-far 1))))) 69 | (else 70 | (apply loop 71 | (resume manager-cor walks-so-far))))) 72 | (else 73 | (apply loop 74 | (resume other-location-cor 75 | (list #f (+ walks-so-far 1))))))))))) 76 | } 77 | 78 | \n Each location starts off with one umbrella (\q{num-umbrellas = 79 | 1}). Each resumption to the location (whether at the start, or 80 | after a walk from the other location) comes with the following 81 | info: Whether an umbrella arrived with the latest walk, and the 82 | tally of the walks achieved so far. The former causes the 83 | location to update its \q{num-umbrellas}. Next, the location uses 84 | \q{random} to figure out if it’s raining. If it is, it further 85 | checks if has an umbrella to spare. If so, it resumes the other 86 | location, sending the umbrella; if not, it resumes the manager 87 | with the \q{walks-so-far}. If it isn’t raining, it resumes the 88 | other location without an umbrella. 89 | 90 | (There is another, not very probable, possibility: The 91 | \q{walks-so-far} have reached the maximum, in which case, the 92 | location in question resumes the manager with that number. We 93 | need this to avoid an experiment that takes forever.) 94 | 95 | The managing coroutine starts off one of the location coroutines, 96 | say the home. Since it refers to the home coroutine, we’ll use a 97 | coroutine-genertor procedure for it too, taking the home 98 | coroutine as paramter: 99 | 100 | \scmdribble{ 101 | (define make-manager-cor 102 | (lambda (home-cor) 103 | (coroutine dummy-init-arg 104 | (resume home-cor (list #f 0))))) 105 | } 106 | 107 | \n All it does is start off the professor at his home, and waits 108 | until one of the locations resumes it when the prof has stranded 109 | himself. 110 | 111 | To start off the process, we need to actually generate the three 112 | coroutines, and link them together. 113 | 114 | \verbwrite{ 115 | (define umbrella-trial 116 | (lambda (rain-prob) 117 | (when (number? rain-prob) (set! *rain-prob* rain-prob)) 118 | ;... 119 | } 120 | 121 | \scmdribble{ 122 | (letrec ((home-cor (make-location-cor 123 | (lambda (v) (office-cor v)) 124 | (lambda (v) (manager-cor v)))) 125 | (office-cor (make-location-cor 126 | (lambda (v) (home-cor v)) 127 | (lambda (v) (manager-cor v)))) 128 | (manager-cor (make-manager-cor 129 | (lambda (v) (home-cor v))))) 130 | ;... 131 | } 132 | 133 | \n Note that we use lambda-wrapping, so the argument coroutines have 134 | a chance to be created before being used. 135 | 136 | The body of the letrec then runs the manager 137 | 138 | \scmdribble{ 139 | ;... 140 | (manager-cor 'start-the-ball-rolling) 141 | ) 142 | } 143 | 144 | \verbwrite{ 145 | ;... 146 | ) 147 | } 148 | 149 | This should give the number of walks the prof manages before 150 | getting stranded. We'd like to run this simulation multiple 151 | times, plus we'd like to vary the rain probability.\f{We could, 152 | if we wanted, vary the maximum number of walks too, in the same 153 | way. While we’ve used globals \q{*rain-prob*} and 154 | \q{*max-num-walks*} here to avoid complicating the presentation 155 | of the code, ideally these parameters should be lexically visible 156 | only to the body of \q{umbrella-trial}, with the definitions of 157 | the coroutine-generators moving into \q{umbrella-trial}’s body so 158 | they can access these parameters.} Let's wrap the \q{letrec} inside a 159 | procedure that takes these parameters and returns a thunk that 160 | can be run as one trial. 161 | 162 | \q{ 163 | (define umbrella-trial 164 | (lambda (rain-prob) 165 | (lambda () 166 | (when (number? rain-prob) (set! *rain-prob* rain-prob)) 167 | 168 | ; the letrec expression goes here 169 | ))) 170 | } 171 | 172 | \n We can now call, say 173 | 174 | \q{ 175 | ((umbrella-trial 0.4)) 176 | } 177 | 178 | \n and this will output the number of walks before strandedness. 179 | 180 | To estimate the expected value of the achieved walks, 181 | we can use the \q{monte-carlo} procedure we’ve already defined in 182 | chapter~\ref{rec}: 183 | 184 | \q{ 185 | (monte-carlo (umbrella-trial 0.4)) 186 | } 187 | 188 | \n You will find that Prof F gets stranded in a matter of mere 189 | days, way before the 5-year goal he set himself. What do you 190 | think the result will be if the probability of rain is 0 or 1? 191 | What if it is a little more than 0 or a little less than 1? Well, 192 | you don’t have to puzzle over it. Just call \q{monte-carlo} on 193 | \q{umbrella-trial} with the appropriate argument! 194 | -------------------------------------------------------------------------------- /io.tex: -------------------------------------------------------------------------------- 1 | \chapter{I/O} 2 | 3 | \index{port} 4 | Scheme has input/output (I/O) procedures that will let you 5 | read from an input port or write to an output port. Ports 6 | can be associated with the console, files or strings. 7 | 8 | \section{Reading} 9 | 10 | Scheme’s reader procedures take an optional input port 11 | argument. If the port is not specified, the current input 12 | port (usually the console) is assumed. 13 | 14 | \index{eof-object?@\q{eof-object?}} 15 | 16 | Reading can be character-, line- or s-expression-based. 17 | Each time a read is performed, the port’s state changes so 18 | that the next read will read material following what was 19 | already read. If the port has no more material to be read, 20 | the reader procedure returns a specific datum called the 21 | end-of-file or eof object. This datum is the only value 22 | that satisfies the \q{eof-object?} predicate. 23 | 24 | \index{read-char@\q{read-char}} 25 | \index{read-line@\q{read-line}} 26 | \index{read@\q{read}} 27 | 28 | The procedure \q{read-char} reads the next character from 29 | the port. \q{read-line} reads the next line, returning it 30 | as a string (the final newline is not included). The 31 | procedure \q{read} reads the next s-expression. 32 | 33 | \section{Writing} 34 | 35 | Scheme’s writer procedures take the object that is to be 36 | written and an optional output port argument. If the port 37 | is not specified, the current output port (usually the 38 | console) is assumed. 39 | 40 | Writing can be character- or s-expression-based. 41 | 42 | \index{write-char@\q{write-char}} 43 | 44 | The procedure \q{write-char} writes the given character 45 | (without the \p{#\}) to the output port. 46 | 47 | \index{write@\q{write}} 48 | \index{display@\q{display}} 49 | \index{newline@\q{newline}} 50 | 51 | The procedures \q{write} and \q{display} both 52 | write the given s-expression to the port, with one 53 | difference: \q{write} attempts to use a machine-readable 54 | format and \q{display} doesn’t. E.g., \q{write} uses double 55 | quotes for strings and the \p{#\} syntax for characters. 56 | \q{display} doesn’t. 57 | 58 | The procedure \q{newline} starts a new line on 59 | the output port. 60 | 61 | \index{port!for file} 62 | \index{file!port for} 63 | 64 | \section{File ports} 65 | 66 | \index{current-input-port@\q{current-input-port}} 67 | \index{current-output-port@\q{current-output-port}} 68 | \index{standard input} 69 | \index{standard output} 70 | Scheme’s I/O procedures do not need a port argument if the 71 | port happens to be standard input or standard output. 72 | However, if you need these ports explicitly, the 73 | zero-argument procedures \q{current-input-port} and 74 | \q{current-output-port} furnish them. Thus, 75 | 76 | \q{ 77 | (display 9) 78 | (display 9 (current-output-port)) 79 | } 80 | 81 | \n have the same behavior. 82 | 83 | \index{open-input-file@\q{open-input-file}} 84 | \index{open-output-file@\q{open-output-file}} 85 | 86 | A port is associated with a file by {\em opening} the file. 87 | The procedure \q{open-input-file} takes a filename argument 88 | and returns a new input port associated with it. The 89 | procedure \q{open-output-file} takes a filename argument and 90 | returns a new output port associated with it. It is an 91 | error to open an input file that doesn’t exist, or to open 92 | an output file that already exists. 93 | 94 | \index{close-input-port@\q{close-input-port}} 95 | \index{close-output-port@\q{close-output-port}} 96 | 97 | After you have performed I/O on a port, you should close it 98 | with \q{close-input-port} or \q{close-output-port}. 99 | 100 | In the following, assume the file \p{hello.txt} contains the 101 | single word \q{hello}. 102 | 103 | \q{ 104 | (define i (open-input-file "hello.txt")) 105 | 106 | (read-char i) 107 | |evalsto #\h 108 | 109 | (define j (read i)) 110 | 111 | j 112 | |evalsto ello 113 | } 114 | 115 | Assume the file \p{greeting.txt} does not exist before the 116 | following programs are fed to the listener: 117 | 118 | \q{ 119 | (define o (open-output-file "greeting.txt")) 120 | 121 | (display "hello" o) 122 | (write-char #\space o) 123 | (display 'world o) 124 | (newline o) 125 | 126 | (close-output-port o) 127 | } 128 | 129 | \n The file \p{greeting.txt} will now contain the 130 | line: 131 | 132 | \p{ 133 | hello world 134 | } 135 | 136 | \subsection{Automatic opening and closing of file ports} 137 | 138 | \index{call-with-input-file@\q{call-with-input-file}} 139 | \index{call-with-output-file@\q{call-with-output-file}} 140 | Scheme supplies the procedures \q{call-with-input-file} and 141 | \q{call-with-output-file} that will take care of opening a 142 | port and closing it after you’re done with it. 143 | 144 | The procedure \q{call-with-input-file} takes a filename 145 | argument and a procedure. The procedure is applied to an 146 | input port opened on the file. When the procedure 147 | completes, its result is returned after ensuring that the 148 | port is closed. 149 | 150 | \q{ 151 | (call-with-input-file "hello.txt" 152 | (lambda (i) 153 | (let* ((a (read-char i)) 154 | (b (read-char i)) 155 | (c (read-char i))) 156 | (list a b c)))) 157 | |evalsto (#\h #\e #\l) 158 | } 159 | 160 | The procedure \q{call-with-output-file} does the analogous 161 | services for an output file. 162 | 163 | 164 | \index{string!port for} 165 | \index{port!for string} 166 | 167 | \section{String ports} 168 | 169 | \index{open-input-string@\q{open-input-string}} 170 | It is often convenient to associate ports with strings. 171 | Thus, the procedure \q{open-input-string} associates a port 172 | with a given string. Reader procedures on this port will 173 | read off the string: 174 | 175 | \q{ 176 | (define i (open-input-string "hello world")) 177 | 178 | (read-char i) 179 | |evalsto #\h 180 | 181 | (read i) 182 | |evalsto ello 183 | 184 | (read i) 185 | |evalsto world 186 | } 187 | 188 | \index{open-output-string@\q{open-output-string}} 189 | 190 | The procedure \q{open-output-string} creates an 191 | output port that will eventually be used to create a string: 192 | 193 | \q{ 194 | (define o (open-output-string)) 195 | 196 | (write 'hello o) 197 | (write-char #\, o) 198 | (display " " o) 199 | (display "world" o) 200 | } 201 | 202 | \index{get-output-string@\q{get-output-string}} 203 | 204 | You can now use the procedure \q{get-output-string} to get 205 | the accumulated string in the string port \q{o}: 206 | 207 | \q{ 208 | (get-output-string o) 209 | |evalsto "hello, world" 210 | } 211 | 212 | String ports need not be explicitly closed. 213 | 214 | \index{file!loading} 215 | \index{load@\q{load}} 216 | 217 | \section{Loading files} 218 | 219 | We have already seen the procedure \q{load} that loads 220 | files containing Scheme code. {\em Loading} a file 221 | consists in evaluating in sequence every Scheme form in 222 | the file. The pathname argument given to \q{load} is 223 | reckoned relative to the current working directory of 224 | Scheme, which is normally the directory in which the 225 | Scheme executable was called. 226 | 227 | Files can load other files, and this is useful in a 228 | large program spanning many files. Unfortunately, 229 | unless full pathnames are used, the argument file of a 230 | \q{load} is dependent on Scheme’s current 231 | directory. Supplying full pathnames is not always 232 | convenient, because we would like to move the program 233 | files as a unit (preserving their relative pathnames), 234 | perhaps to many different machines. 235 | 236 | \index{load-relative@\q{load-relative}} 237 | 238 | MzScheme provides the \q{load-relative} procedure that 239 | greatly helps in fixing the files to be loaded. 240 | \q{load-relative}, like \q{load}, takes a pathname 241 | argument. When a \q{load-relative} call occurs in a 242 | file \q{foo.scm}, the path of its argument is reckoned 243 | from the directory of the calling file \q{foo.scm}. In 244 | particular, this pathname is reckoned independent of 245 | Scheme’s current directory, and thus allows convenient 246 | multifile program development. 247 | -------------------------------------------------------------------------------- /let.tex: -------------------------------------------------------------------------------- 1 | \chapter{Lexical variables} 2 | 3 | \index{variable!lexical} 4 | \index{variable!local} 5 | \index{variable!global} 6 | Scheme’s variables have lexical scope, i.e., they are 7 | visible only to forms within a certain contiguous 8 | stretch of program text. The {\em global} variables we 9 | have seen thus far are no exception: Their scope is all 10 | program text, which is certainly contiguous. 11 | 12 | We have also seen some examples of {\em local} 13 | variables. These were the \q{lambda} parameters, which 14 | get {\em bound} each time the procedure is called, and 15 | whose scope is that procedure’s body. E.g., 16 | 17 | \q{ 18 | (define x 9) 19 | (define add2 (lambda (x) (+ x 2))) 20 | 21 | x |evalsto 9 22 | 23 | (add2 3) |evalsto 5 24 | (add2 x) |evalsto 11 25 | 26 | x |evalsto 9 27 | } 28 | 29 | Here, there is a global \q{x}, and there is also a 30 | local \q{x}, the latter introduced by procedure 31 | \q{add2}. The global \q{x} is always 32 | \q{9}. The local \q{x} gets bound to \q{3} in the 33 | first call to \q{add2} and to the value of the global 34 | \q{x}, i.e., \q{9}, in the second call to \q{add2}. 35 | When the procedure calls return, the global \q{x} 36 | continues to be \q{9}. 37 | 38 | The form \q{set!} modifies the lexical binding of a 39 | variable. 40 | 41 | \q{ 42 | (set! x 20) 43 | } 44 | 45 | \n modifies the global binding of \q{x} from \q{9} to 46 | \q{20}, because that is the binding of \q{x} that is 47 | visible to \q{set!}. If the \q{set!} was inside 48 | \q{add2}’s body, it would have modified the local 49 | \q{x}: 50 | 51 | \q{ 52 | (define add2 53 | (lambda (x) 54 | (set! x (+ x 2)) 55 | x)) 56 | } 57 | 58 | The \q{set!} here adds \q{2} to the local variable 59 | \q{x}, and the procedure returns this new value of the local \q{x}. (In terms of effect, 60 | this procedure is indistinguishable from the previous 61 | \q{add2}.) We can call \q{add2} on the 62 | global \q{x}, as before: 63 | 64 | \q{ 65 | (add2 x) |evalsto 22 66 | } 67 | 68 | \n (Remember global \q{x} is now \q{20}, not \q{9}!) 69 | 70 | The \q{set!} inside \q{add2} affects only the local 71 | variable used by \q{add2}. Although the local variable 72 | \q{x} got its binding from the global \q{x}, 73 | the latter is unaffected by the \q{set!} to the local 74 | \q{x}. 75 | 76 | \q{ 77 | x |evalsto 20 78 | } 79 | 80 | Note that we had all this discussion because we used 81 | the same identifier for a local variable and a global 82 | variable. In any text, an identifier named \q{x} refers 83 | to the lexically closest variable named \q{x}. This 84 | will {\em shadow} any outer or global \q{x}’s. E.g., 85 | in \q{add2}, the parameter \q{x} shadows the global 86 | \q{x}. 87 | 88 | A procedure’s body can access and modify variables in 89 | its surrounding scope provided the procedure’s 90 | parameters don’t shadow them. This can give some 91 | interesting programs. E.g., 92 | 93 | \q{ 94 | (define counter 0) 95 | 96 | (define bump-counter 97 | (lambda () 98 | (set! counter (+ counter 1)) 99 | counter)) 100 | } 101 | 102 | The procedure \q{bump-counter} is a zero-argument 103 | procedure (also called a {\em thunk}). It introduces 104 | no local variables, and thus cannot shadow anything. 105 | Each time it is called, it modifies the {\em global} 106 | variable 107 | \q{counter} — it increments it by 1 — and returns 108 | its current value. Here are some successive calls to 109 | \q{bump-counter}: 110 | 111 | \q{ 112 | (bump-counter) |evalsto 1 113 | (bump-counter) |evalsto 2 114 | (bump-counter) |evalsto 3 115 | } 116 | 117 | \index{let@\q{let}} 118 | \index{let*@\q{let*}} 119 | \section{\q{let} and \q{let*}} 120 | 121 | Local variables can be introduced without explicitly 122 | creating a procedure. The special form \q{let} 123 | introduces a list of local variables for use within its 124 | body: 125 | 126 | \q{ 127 | (let ((x 1) 128 | (y 2) 129 | (z 3)) 130 | (list x y z)) 131 | |evalsto (1 2 3) 132 | } 133 | 134 | \n As with \q{lambda}, within the \q{let}-body, the local 135 | \q{x} (bound to \q{1}) shadows the global \q{x} (which 136 | is bound to \q{20}). 137 | 138 | The local variable initializations — \q{x} to \q{1}; 139 | \q{y} to \q{2}; \q{z} to \q{3} — are not considered 140 | part of the \q{let} body. Therefore, a reference to 141 | \q{x} in the initialization will refer to the global, 142 | not the local \q{x}: 143 | 144 | \q{ 145 | (let ((x 1) 146 | (y x)) 147 | (+ x y)) 148 | |evalsto 21 149 | } 150 | 151 | \n This is because \q{x} is bound to \q{1}, and \q{y} is 152 | bound to the {\em global} \q{x}, which is \q{20}. 153 | 154 | Sometimes, it is convenient to have \q{let}’s list of 155 | lexical variables be introduced in sequence, so that 156 | the initialization of a later variable occurs in the 157 | {\em lexical scope} of earlier variables. The form 158 | \q{let*} does this: 159 | 160 | \q{ 161 | (let* ((x 1) 162 | (y x)) 163 | (+ x y)) 164 | |evalsto 2 165 | } 166 | 167 | \n The \q{x} in \q{y}’s initialization refers to the \q{x} 168 | just above. The example is entirely equivalent to — 169 | and is in fact intended to be a convenient abbreviation 170 | for — the following program with nested \q{let}s: 171 | 172 | \q{ 173 | (let ((x 1)) 174 | (let ((y x)) 175 | (+ x y))) 176 | |evalsto 2 177 | } 178 | 179 | The values bound to lexical variables can be 180 | procedures: 181 | 182 | \q{ 183 | (let ((cons (lambda (x y) (+ x y)))) 184 | (cons 1 2)) 185 | |evalsto 3 186 | } 187 | 188 | \n Inside this \q{let} body, the lexical variable \q{cons} 189 | adds its arguments. Outside, \q{cons} continues to 190 | create dotted pairs. 191 | 192 | \index{fluid-let@\q{fluid-let}} 193 | 194 | \section{\q{fluid-let}} 195 | \label{fluid-let} 196 | 197 | A lexical variable is visible throughout its scope, 198 | provided it isn’t shadowed. Sometimes, it is helpful 199 | to {\em temporarily} set a lexical variable to a 200 | certain value. For this, we use the form 201 | \q{fluid-let}.\f{\q{fluid-let} is a nonstandard special 202 | form. See section~\ref{fluid-let-macro} for a definition 203 | of \q{fluid-let} in Scheme.} 204 | 205 | \q{ 206 | (fluid-let ((counter 99)) 207 | (display (bump-counter)) (newline) 208 | (display (bump-counter)) (newline) 209 | (display (bump-counter)) (newline)) 210 | } 211 | 212 | \n 213 | This looks similar to a \q{let}, but instead of 214 | shadowing the global variable \q{counter}, it 215 | temporarily sets it to \q{99} before continuing with 216 | the 217 | \q{fluid-let} body. Thus the \q{display}s in the body 218 | produce 219 | 220 | \p{ 221 | 100 222 | 101 223 | 102 224 | } 225 | 226 | \n After the \q{fluid-let} expression has evaluated, 227 | the global \q{counter} reverts to the value it had 228 | before the \q{fluid-let}. 229 | 230 | \q{ 231 | counter |evalsto 3 232 | } 233 | 234 | Note that \q{fluid-let} has an entirely different 235 | effect from \q{let}. \q{fluid-let} does not introduce 236 | new lexical variables like \q{let} does. It modifies 237 | the bindings of {\em existing} lexical variables, and 238 | the modification ceases as soon as the \q{fluid-let} does. 239 | 240 | To drive home this point, consider the program 241 | 242 | \q{ 243 | (let ((counter 99)) 244 | (display (bump-counter)) (newline) 245 | (display (bump-counter)) (newline) 246 | (display (bump-counter)) (newline)) 247 | } 248 | 249 | \n which substitutes \q{let} for \q{fluid-let} in 250 | the previous example. The output is now 251 | 252 | \q{ 253 | 4 254 | 5 255 | 6 256 | } 257 | 258 | \n I.e., the global \q{counter}, which is initially 259 | \q{3}, is updated by each call to \q{bump-counter}. 260 | The new lexical variable \q{counter}, with its 261 | initialization of \q{99}, has no impact on the calls to 262 | \q{bump-counter}, because although the calls to 263 | \q{bump-counter} are within the scope of this local 264 | \q{counter}, the body of \q{bump-counter} isn’t. The 265 | latter continues to refer to the {\em global} 266 | \q{counter}, whose final value is \q{6}. 267 | 268 | \q{ 269 | counter |evalsto 6 270 | } 271 | 272 | \input prng 273 | -------------------------------------------------------------------------------- /rec.tex: -------------------------------------------------------------------------------- 1 | \chapter{Recursion} 2 | \label{rec} 3 | 4 | \index{recursion} 5 | \index{procedure!recursive} 6 | A procedure body can contain calls to other procedures, 7 | not least itself: 8 | 9 | \q{ 10 | (define factorial 11 | (lambda (n) 12 | (if (= n 0) 1 13 | (* n (factorial (- n 1)))))) 14 | } 15 | 16 | \n This {\em recursive} procedure calculates the {\em 17 | factorial} of a number. If the number is \q{0}, the 18 | answer is \q{1}. For any other number \q{n}, the 19 | procedure uses itself to calculate the factorial of 20 | \q{n - 1}, multiplies that subresult by \q{n}, and 21 | returns the product. 22 | 23 | Mutually recursive procedures are also possible. The 24 | following predicates for evenness and oddness use each 25 | other: 26 | 27 | \q{ 28 | (define is-even? 29 | (lambda (n) 30 | (if (= n 0) #t 31 | (is-odd? (- n 1))))) 32 | 33 | (define is-odd? 34 | (lambda (n) 35 | (if (= n 0) #f 36 | (is-even? (- n 1))))) 37 | } 38 | 39 | \index{even?@\q{even?}} 40 | \index{odd?@\q{odd?}} 41 | 42 | These definitions are offered here only as simple 43 | illustrations of mutual recursion. Scheme already 44 | provides the primitive predicates \q{even?} and 45 | \q{odd?}. 46 | 47 | \index{letrec@\q{letrec}} 48 | \index{recursion!letrec@\q{letrec}} 49 | 50 | \section{\q{letrec}} 51 | 52 | If we wanted the above procedures as local 53 | variables, we could try to use a \q{let} form: 54 | 55 | \q{ 56 | (let ((local-even? (lambda (n) 57 | (if (= n 0) #t 58 | (local-odd? (- n 1))))) 59 | (local-odd? (lambda (n) 60 | (if (= n 0) #f 61 | (local-even? (- n 1)))))) 62 | (list (local-even? 23) (local-odd? 23))) 63 | } 64 | 65 | \n This won’t quite work, because the occurrences of 66 | \q{local-even?} and \q{local-odd?} in the initializations 67 | don’t refer to the lexical variables themselves. 68 | Changing the \q{let} to a \q{let*} won’t work either, 69 | for while the \q{local-even?} inside \q{local-odd?}’s body 70 | refers to the correct procedure value, the \q{local-odd?} 71 | in \q{local-even?}’s body still points elsewhere. 72 | 73 | To solve problems like this, Scheme provides the form 74 | \q{letrec}: 75 | 76 | \q{ 77 | (letrec ((local-even? (lambda (n) 78 | (if (= n 0) #t 79 | (local-odd? (- n 1))))) 80 | (local-odd? (lambda (n) 81 | (if (= n 0) #f 82 | (local-even? (- n 1)))))) 83 | (list (local-even? 23) (local-odd? 23))) 84 | } 85 | 86 | \n The lexical variables introduced by a \q{letrec} are 87 | visible not only in the \q{letrec}-body but also within 88 | all the initializations. \q{letrec} is thus 89 | tailor-made for defining recursive and mutually 90 | recursive local procedures. 91 | 92 | \index{named let@named \q{let}} 93 | \index{let@\q{let}!named} 94 | 95 | \section{Named \q{let}} 96 | 97 | A recursive procedure defined using \q{letrec} can 98 | describe loops. Let’s say we want to display a 99 | countdown from \q{10}: 100 | 101 | \q{ 102 | (letrec ((countdown (lambda (i) 103 | (if (= i 0) 'liftoff 104 | (begin 105 | (display i) 106 | (newline) 107 | (countdown (- i 1))))))) 108 | (countdown 10)) 109 | } 110 | 111 | \n This outputs on the console the numbers \q{10} down to 112 | \q{1}, and returns the result \q{liftoff}. 113 | 114 | Scheme allows a variant of \q{let} called {\em named} 115 | \q{let} to write this kind of loop more compactly: 116 | 117 | \q{ 118 | (let countdown ((i 10)) 119 | (if (= i 0) 'liftoff 120 | (begin 121 | (display i) 122 | (newline) 123 | (countdown (- i 1))))) 124 | } 125 | 126 | \n Note the presence of a variable identifying the loop 127 | immediately after the \q{let}. This program is 128 | equivalent to the one written with \q{letrec}. You may 129 | consider the named \q{let} to be a macro 130 | (chapter~\ref{sugar}) expanding to the \q{letrec} form. 131 | 132 | \index{iteration} 133 | \index{loop} 134 | \index{recursion!iteration as} 135 | \index{tail recursion} 136 | \index{recursion!tail} 137 | \index{tail call} 138 | \index{tail call!elimination of} 139 | \index{procedure!tail-recursive} 140 | 141 | \section{Iteration} 142 | 143 | \q{countdown} defined above is really a recursive 144 | procedure. Scheme can define loops only through 145 | recursion. There are no special looping or iteration 146 | constructs. 147 | 148 | Nevertheless, the loop as defined above is a {\em 149 | genuine} loop, in exactly the same way that other 150 | languages bill their loops. I.e., Scheme takes special 151 | care to ensure that recursion of the type used above 152 | will not generate the procedure call/return overhead. 153 | 154 | Scheme does this by a process called {\em tail-call 155 | elimination}. If you look closely at the \q{countdown} 156 | procedure, you will note that when the recursive call 157 | occurs in \q{countdown}’s body, it is the {\em tail call}, 158 | or the very last thing done — each invocation of 159 | \q{countdown} either does not call itself, or when it 160 | does, it does so as its very last act. To a Scheme 161 | implementation, this makes the recursion 162 | indistinguishable from iteration. So go ahead, use 163 | recursion to write loops. It’s safe. 164 | 165 | Here’s another example of a useful tail-recursive 166 | procedure: 167 | 168 | \index{list-position@\q{list-position}} 169 | \scmfilename listpos.scm 170 | \scmdribble{ 171 | (define list-position 172 | (lambda (o l) 173 | (let loop ((i 0) (l l)) 174 | (if (null? l) #f 175 | (if (eqv? (car l) o) i 176 | (loop (+ i 1) (cdr l))))))) 177 | } 178 | 179 | \n \q{list-position} finds the index of the first 180 | occurrence of the object \q{o} in the list \q{l}. If 181 | the object is not found in the list, the procedure 182 | returns \q{#f}. 183 | 184 | Here’s yet another tail-recursive procedure, one that 185 | reverses its argument list “in place”, i.e., by mutating 186 | the contents of the existing list, and without 187 | allocating a new one: 188 | 189 | \index{reverse"!@\q{reverse"!}} 190 | \scmfilename reverseb.scm 191 | \scmdribble{ 192 | (define reverse! 193 | (lambda (s) 194 | (let loop ((s s) (r '())) 195 | (if (null? s) r 196 | (let ((d (cdr s))) 197 | (set-cdr! s r) 198 | (loop d s)))))) 199 | } 200 | 201 | \n 202 | (\q{reverse!} is a useful enough procedure that it is 203 | provided primitively in many Scheme dialects, e.g., 204 | MzScheme and Guile.) 205 | 206 | \index{Monte Carlo simulation} 207 | In the last chapter, we defined two procedures \q{throw-one-die} 208 | and \q{throw-two-dice} that returned the result of a single 209 | experiment, i.e., a single throw of one or two dice. What if we 210 | want to find the {\em expected} result, and we don't want to do the 211 | calculations? One way, the so-called Monte Carlo method, is to 212 | use iteration to 213 | run the experiment many (e.g., 10000) times, and average the results. 214 | 215 | \scmfilename montecarlo.scm 216 | 217 | \scmdribble{ 218 | (define *num-trials* 10000) 219 | 220 | (define monte-carlo 221 | (lambda (experiment) 222 | (let loop ((i 0) (acc 0.0)) 223 | (if (= i *num-trials*) 224 | (/ acc *num-trials*) 225 | (loop (+ i 1) (+ acc (experiment))))))) 226 | } 227 | 228 | \n Now run 229 | 230 | \q{ 231 | (monte-carlo throw-one-die) |evalsto 3.4728 232 | (monte-carlo throw-two-dice) |evalsto 6.9994 233 | } 234 | 235 | \n The expected values should be close to 3.5 and 7 respectively. 236 | 237 | For some numerical-calculus examples of recursion (including iteration), 238 | see appendix~\ref{numint}. 239 | 240 | \index{map@\q{map}} 241 | \index{for-each@\q{for-each}} 242 | 243 | \section{Mapping a procedure across a list} 244 | 245 | A special kind of iteration involves repeating the same 246 | action for each element of a list. Scheme offers two 247 | procedures for this situation: \q{map} and \q{for-each}. 248 | 249 | The \q{map} procedure applies a given procedure to every 250 | element of a given list, and returns the list of the 251 | results. E.g., 252 | 253 | \q{ 254 | (map add2 '(1 2 3)) 255 | |evalsto (3 4 5) 256 | } 257 | 258 | The \q{for-each} procedure also applies a procedure to each 259 | element in a list, but returns void. The procedure 260 | application is done purely for any side-effects it may 261 | cause. E.g., 262 | 263 | \q{ 264 | (for-each display 265 | (list "one " "two " "buckle my shoe")) 266 | } 267 | 268 | \n has the side-effect of displaying the strings (in 269 | the order they appear) on the console. 270 | 271 | The procedures applied by \q{map} and \q{for-each} 272 | need not be one-argument procedures. For example, 273 | given an \q{n}-argument procedure, \q{map} 274 | takes \q{n} lists and applies the procedure to 275 | every set of \q{n} of arguments selected from across 276 | the lists. E.g., 277 | 278 | \q{ 279 | (map cons '(1 2 3) '(10 20 30)) 280 | |evalsto ((1 . 10) (2 . 20) (3 . 30)) 281 | 282 | (map + '(1 2 3) '(10 20 30)) 283 | |evalsto (11 22 33) 284 | } 285 | -------------------------------------------------------------------------------- /script.tex: -------------------------------------------------------------------------------- 1 | \chapter{Shell scripts} 2 | \label{script} 3 | 4 | \index{script} 5 | It is often convenient to simply write what one wants 6 | done into a file or {\em script}, and execute the 7 | script as though it were any other operating-system 8 | shell command. The interface to more weighty programs 9 | is often provided in the form of a script, and users 10 | frequently build their own scripts or customize 11 | existing ones to suit particular needs. Scripting is 12 | arguably the most frequent programming task performed. 13 | For many users, it is the only programming they will 14 | ever do. 15 | 16 | Operating systems such as Unix and DOS (the 17 | command-line interface provided in Windows) 18 | provide such a scripting mechanism, but the scripting 19 | language in both cases is very rudimentary. Often a 20 | script is just a sequence or {\em batch} of commands 21 | that one would type to the shell prompt. It saves the 22 | user from having to type every one of the shell 23 | commands individually each time they require the same 24 | or similar sequence to be performed. Some scripting 25 | languages throw in a small amount of programmability in 26 | the form of a conditional and a loop, but that is about 27 | all. This is enough for smallish tasks, but as one’s 28 | scripts become bigger and more demanding, as scripts 29 | invariably seem to do, one often feels the need for a 30 | fuller fledged programming language. A Scheme with an 31 | adequate operating-system interface makes scripting 32 | easy and maintainable. 33 | 34 | This section will describe how to write scripts in 35 | Scheme. Since there is wide variation in the various 36 | Scheme dialects on how to accomplish this, we will 37 | concentrate on the MzScheme dialect, and document in 38 | appendix~\ref{dialect} the modifications needed for 39 | other dialects. We will also concentrate on the Unix 40 | operating system for the moment; appendix~\ref{dos} 41 | will deal with the DOS counterpart. 42 | 43 | \section{Hello, World!, again} 44 | 45 | We will now create a Scheme script that says hello to 46 | the world. Saying hello is of course not a demanding 47 | scripting problem for traditional scripting languages. 48 | However, understanding how to transcribe it into Scheme 49 | will launch us on the path to more ambitious scripts. 50 | First, a conventional Unix hello script is a file, with 51 | contents that look like: 52 | 53 | \p{ 54 | echo Hello, World! 55 | } 56 | 57 | \n It uses the shell command \p{echo}. The script can be 58 | named \p{hello}, made into an executable by doing 59 | 60 | \p{ 61 | chmod +x hello 62 | } 63 | 64 | \n and placed in one of 65 | the directories named in the \p{PATH} environment 66 | variable. Thereafter, anytime one types 67 | 68 | \p{ 69 | hello 70 | } 71 | 72 | \n at the shell prompt, one promptly gets the 73 | insufferable greeting. 74 | 75 | A Scheme hello script will perform the same output 76 | using Scheme (using the program in chapter~\ref{hello}), 77 | but we need something in the file to inform the 78 | operating system that it needs to construe the commands 79 | in the file as Scheme, and not as its default script 80 | language. The Scheme script file, also called 81 | \p{hello}, looks like: 82 | 83 | \p{ 84 | ":"; exec mzscheme -r $0 "$@" 85 | 86 | (display "Hello, World!") 87 | (newline)) 88 | } 89 | 90 | \n Everything following the first line is straight 91 | Scheme. However, the first line is the magic that 92 | makes this into a script. When the user types 93 | \p{hello} at the Unix prompt, Unix will read the file 94 | as a regular script. The first thing it sees is the 95 | \p{":"}, which is a shell no-op. The \p{;} is the shell 96 | command separator. The next shell command is the 97 | \p{exec}. \p{exec} tells Unix to abandon the 98 | current script and run \p{mzscheme -r $0 "$@"} instead, 99 | where the parameter \p{$0} will be replaced by the name 100 | of the script, and the parameter \p{"$@"} will be 101 | replaced by the list of arguments given by the user to 102 | the script. (In this case, there are no such 103 | arguments.) 104 | 105 | We have now, in effect, transformed the \p{hello} shell 106 | command into a different shell command, viz., 107 | 108 | \p{ 109 | mzscheme -r /whereveritis/hello 110 | } 111 | 112 | \n where \p{/whereveritis/hello} is the pathname of \p{hello}. 113 | 114 | \p{mzscheme} calls the MzScheme executable. The \p{-r} 115 | option tells it to load the immediately following 116 | argument as a Scheme file after collecting any 117 | succeeding arguments into a vector called \q{argv}. 118 | (In this example, \q{argv} will be the null vector.) 119 | 120 | Thus, the Scheme script will be run as a Scheme file, 121 | and the Scheme forms in the file will have access to 122 | the script’s original arguments via the vector 123 | \q{argv}. 124 | 125 | Now, Scheme has to tackle the first line in the script, 126 | which as we’ve already seen, was really a well-formed, 127 | {\em traditional} shell script. The \q{":"} is a 128 | self-evaluating string in Scheme and thus harmless. 129 | The 130 | ‘\p{;}’ marks a Scheme comment, and so the \p{exec ...} is 131 | safely ignored. The rest of the file is of course 132 | straight Scheme, and the expressions therein are 133 | evaluated in sequence. After all of them have been 134 | evaluated, Scheme will exit. 135 | 136 | In sum, typing \p{hello} at the shell prompt will produce 137 | 138 | \p{ 139 | Hello, World! 140 | } 141 | 142 | \n and return you to the shell prompt. 143 | 144 | \section{Scripts with arguments} 145 | 146 | A Scheme script uses the variable \q{argv} to refer to 147 | its arguments. For example, the following script 148 | echoes all its arguments, each on a line: 149 | 150 | \q{ 151 | ":"; exec mzscheme -r $0 "$@" 152 | 153 | ;Put in argv-count the number of arguments supplied 154 | 155 | (define argv-count (vector-length argv)) 156 | 157 | (let loop ((i 0)) 158 | (unless (>= i argv-count) 159 | (display (vector-ref argv i)) 160 | (newline) 161 | (loop (+ i 1)))) 162 | } 163 | 164 | Let’s call this script \p{echoall}. Calling \p{echoall 165 | 1 2 3} will display 166 | 167 | \p{ 168 | 1 169 | 2 170 | 3 171 | } 172 | 173 | \n Note that the script name (\q{"echoall"}) is {\em not} included in 174 | the argument vector. 175 | 176 | \section{Example} 177 | 178 | Let’s now tackle a more substantial problem. We need 179 | to transfer files from one computer to another and the 180 | only method we have is to use a 3.5'' floppy as a 181 | ferry. We need a script \p{split4floppy} that will 182 | split files larger than 1.44 million bytes into 183 | floppy-sized chunks. The script file \p{split4floppy} 184 | is as follows: 185 | 186 | \q{ 187 | ":";exec mzscheme -r $0 "$@" 188 | 189 | ;floppy-size = number of bytes that will comfortably fit on a 190 | ; 3.5" floppy 191 | 192 | (define floppy-size 1440000) 193 | 194 | ;split splits the bigfile f into the smaller, floppy-sized 195 | ;subfiles, viz., subfile-prefix.1, subfile-prefix.2, etc. 196 | 197 | (define split 198 | (lambda (f subfile-prefix) 199 | (call-with-input-file f 200 | (lambda (i) 201 | (let loop ((n 1)) 202 | (if (copy-to-floppy-sized-subfile i subfile-prefix n) 203 | (loop (+ n 1)))))))) 204 | 205 | ;copy-to-floppy-sized-subfile copies the next 1.44 million 206 | ;bytes (if there are less than that many bytes left, it 207 | ;copies all of them) from the big file to the nth 208 | ;subfile. Returns true if there are bytes left over, 209 | ;otherwise returns false. 210 | 211 | (define copy-to-floppy-sized-subfile 212 | (lambda (i subfile-prefix n) 213 | (let ((nth-subfile (string-append subfile-prefix "." 214 | (number->string n)))) 215 | (if (file-exists? nth-subfile) (delete-file nth-subfile)) 216 | (call-with-output-file nth-subfile 217 | (lambda (o) 218 | (let loop ((k 1)) 219 | (let ((c (read-char i))) 220 | (cond ((eof-object? c) #f) 221 | (else 222 | (write-char c o) 223 | (if (< k floppy-size) 224 | (loop (+ k 1)) 225 | #t)))))))))) 226 | 227 | ;bigfile = script’s first arg 228 | ; = the file that needs splitting 229 | 230 | (define bigfile (vector-ref argv 0)) 231 | 232 | ;subfile-prefix = script’s second arg 233 | ; = the basename of the subfiles 234 | 235 | (define subfile-prefix (vector-ref argv 1)) 236 | 237 | ;Call split, making subfile-prefix.{1,2,3,...} from 238 | ;bigfile 239 | 240 | (split bigfile subfile-prefix) 241 | } 242 | 243 | \n Script \p{split4floppy} is called as follows: 244 | 245 | \p{ 246 | split4floppy largefile chunk 247 | } 248 | 249 | \n This splits \p{largefile} into subfiles \p{chunk.1}, 250 | \p{chunk.2}, ..., such that each subfile fits on a 251 | floppy. 252 | 253 | After the \p{chunk.i} have been ferried over to the 254 | target computer, the file \p{largefile} can be 255 | retrieved by stringing the \p{chunk.i} together. This 256 | can be done on Unix with: 257 | 258 | \p{ 259 | cat chunk.1 chunk.2 ... > largefile 260 | } 261 | 262 | \n and on DOS with: 263 | 264 | \p{ 265 | copy /b chunk.1+chunk.2+... largefile 266 | } 267 | 268 | -------------------------------------------------------------------------------- /dialect.tex: -------------------------------------------------------------------------------- 1 | % last change: 2020-11-13 2 | \chapter{Scheme dialects} 3 | \label{dialect} 4 | 5 | \index{dialects of Scheme} 6 | \index{R5RS} 7 | All major Scheme dialects implement the R5RS 8 | specification \cite{r5rs}. By using only the features 9 | documented in the R5RS, one can write Scheme code that 10 | is portable across the dialects. However, the R5RS, 11 | either for want of consensus or because of inevitable 12 | system dependencies, remains silent on several matters 13 | that non-trivial programming cannot ignore. The 14 | various dialects have therefore had to solve these 15 | matters in a non-standard and idiosyncratic manner. 16 | 17 | \index{MzScheme} 18 | 19 | This book uses the MzScheme \cite{mzscheme} 20 | dialect of Scheme, and thereby uses several 21 | features that are nonstandard. The complete 22 | list of the dialect-dependent features used 23 | in this book is: the command-line (both for 24 | opening a listener session and for shell scripts), 25 | \q{define-macro}, \q{delete-file}, \q{file-exists?}, 26 | \q{file-or-directory-modify-seconds}, \q{fluid-let}, 27 | \q{gensym}, \q{getenv}, \q{get-output-string}, 28 | \q{load-relative}, \q{open-input-string}, 29 | \q{open-output-string}, \q{read-line}, \q{reverse!}, 30 | \q{system}, \q{unless} and \q{when}. 31 | 32 | All but two of these 33 | are present in the default environment of MzScheme. The missing two, 34 | \q{define-macro} and \q{system}, are provided in 35 | standard MzScheme libraries, which can be explicitly loaded into 36 | MzScheme using the forms: 37 | 38 | \q{ 39 | (require (lib "defmacro.ss")) ;provides define-macro 40 | (require (lib "process.ss")) ;provides system 41 | } 42 | 43 | \n A good place to place these forms is the MzScheme 44 | {\em initialization file} (or {\em init file}), which, on Unix, is the file 45 | \p{.mzschemerc} in the user’s home directory.\f{We will 46 | use \p{~/filename} to denote the file called 47 | \p{filename} in the user’s home directory.} 48 | 49 | Some of the nonstandard features (e.g., \q{file-exists?}, 50 | \q{delete-file}) are in fact de facto standards and are present 51 | in many Schemes. Some other features (e.g., \q{when}, 52 | \q{unless}) have more or less “plug-in” definitions 53 | (given in this book) that can be loaded into any Scheme 54 | dialect that doesn’t have them primitively. The rest 55 | require a dialect-specific definition 56 | (e.g., \q{load-relative}). 57 | 58 | This chapter describes how to incorporate into your 59 | Scheme dialect the nonstandard features used in this 60 | book. For further detail about your Scheme 61 | dialect, consult the documentation provided by its 62 | implementor (appendix~\ref{references}). 63 | 64 | \iffalse 65 | \section{Invocation and init files} 66 | 67 | \index{Guile} 68 | \index{SCM} 69 | \index{STk} 70 | 71 | To invoke the Guile \cite{guile} listener, type \p{guile}. To invoke 72 | SCM \cite{scm}, type \p{scm}. 73 | 74 | To invoke STk \cite{stk}, type \p{snow}. This is the 75 | “no window” executable, which is enough for the purposes 76 | of this book. 77 | \fi 78 | 79 | \index{init file} 80 | 81 | \section{Invocation and init files} 82 | 83 | \index{file-or-directory-modify-seconds@\q{file-or-directory-modify-seconds}} 84 | \index{Guile} 85 | 86 | Like MzScheme, many Scheme dialects load, if 87 | available, an init file, usually supplied in the user’s 88 | home directory. The init file is a convenient location 89 | in which to place definitions for nonstandard features. 90 | E.g., the nonstandard procedure 91 | \q{file-or-directory-modify-seconds} can be added to 92 | the Guile~\cite{guile} dialect of Scheme by putting the 93 | following code in Guile’s init file, which is 94 | \p{~/.guile}: 95 | 96 | \q{ 97 | (define file-or-directory-modify-seconds 98 | (lambda (f) 99 | (vector-ref (stat f) 9))) 100 | } 101 | 102 | Also, the various Scheme dialects have their own 103 | distinctively named commands to invoke their respective 104 | listeners. The following 105 | table lists the invoking commands and init files 106 | for some Scheme dialects: 107 | 108 | \halign{\qquad \hfil # & # & # \cr 109 | {\em Dialect name} & {\em Command} & {\em Init~file} \cr 110 | Bigloo & \p{bigloo} & \p{~/.bigloorc} \cr 111 | Chicken & \p{csi} & \p{~/.csirc} \cr 112 | Gambit & \p{gsi} & \p{~/gambc.scm} \cr 113 | Gauche & \p{gosh} & \p{~/.gaucherc} \cr 114 | Guile & \p{guile} & \p{~/.guile} \cr 115 | Kawa & \p{kawa} & \p{~/.kawarc.scm} \cr 116 | MIT Scheme (Unix) & \p{scheme} & \p{~/.scheme.init} \cr 117 | MIT Scheme (Win) & \p{scheme} & \p{~/scheme.ini} \cr 118 | MzScheme (Unix, Mac OS X) & \p{mzscheme} & \p{~/.mzschemerc} \cr 119 | MzScheme (Win, Mac OS Classic) & \p{mzscheme} & \p{~/mzschemerc.ss} \cr 120 | SCM & \p{scm} & \p{~/ScmInit.scm} \cr 121 | STk & \p{snow} & \p{~/.stkrc} \cr 122 | } 123 | 124 | \iffalse 125 | Note, however, that for the purposes of this text, you 126 | don’t need to insert code into \p{~/.mzschemerc}, 127 | since we don’t use any nonstandard Scheme feature not 128 | already defined in MzScheme. 129 | \fi 130 | 131 | \index{script} 132 | 133 | \section{Shell scripts} 134 | 135 | The initial line for a shell script written in Guile is: 136 | 137 | \q{ 138 | ":";exec guile -s $0 "$@" 139 | } 140 | 141 | In the script, the procedure-call \q{(command-line)} returns 142 | the list of the script’s name and arguments. To access 143 | just the arguments, take the \q{cdr} of this list. 144 | 145 | A Gauche~\cite{gauche} shell script starts out as: 146 | 147 | \q{ 148 | ":"; exec gosh -- $0 "$@" 149 | } 150 | 151 | In the script, the variable \q{*argv*} holds 152 | the list of the script’s arguments. 153 | 154 | A shell script written in SCM starts out as: 155 | 156 | \q{ 157 | ":";exec scm -l $0 "$@" 158 | } 159 | 160 | In the script, the variable \q{*argv*} contains 161 | the list of the Scheme executable name, the script’s 162 | name, the option \p{-l}, and the script’s arguments. 163 | To 164 | access just the arguments, take the \q{cdddr} of this list. 165 | 166 | STk~\cite{stk} shell scripts start out as: 167 | 168 | \q{ 169 | ":";exec snow -f $0 "$@" 170 | } 171 | 172 | In the script, the variable \q{*argv*} contains 173 | the list of the script’s arguments. 174 | 175 | \index{define-macro@\q{define-macro}!in various dialects} 176 | 177 | \section{\q{define-macro}} 178 | \label{dialect-macro} 179 | 180 | \index{Bigloo}\index{Chicken} 181 | \index{Gambit}\index{Gauche}\index{Pocket Scheme} 182 | The \q{define-macro} used in the text occurs in 183 | the Scheme dialects Bigloo \cite{bigloo}, 184 | Chicken~\cite{chicken}, Gambit 185 | \cite{gambit}, Gauche~\cite{gauche}, Guile, MzScheme and Pocket Scheme 186 | \cite{pocketscheme}. There are minor variations in 187 | how macros are defined in the other Scheme dialects. 188 | The rest of this section will point out how these 189 | other dialects notate the following code fragment: 190 | 191 | \q{ 192 | (define-macro MACRO-NAME 193 | (lambda MACRO-ARGS 194 | MACRO-BODY ...)) 195 | } 196 | 197 | \index{MIT Scheme} 198 | 199 | \n In MIT Scheme~\cite{mitscheme} version 7.7.1 and later, this is written as: 200 | 201 | \q{ 202 | (define-syntax MACRO-NAME 203 | (rsc-macro-transformer 204 | (let ((xfmr (lambda MACRO-ARGS MACRO-BODY ...))) 205 | (lambda (e r) 206 | (apply xfmr (cdr e)))))) 207 | } 208 | 209 | \n In older versions of MIT Scheme: 210 | 211 | \q{ 212 | (syntax-table-define system-global-syntax-table 'MACRO-NAME 213 | (macro MACRO-ARGS 214 | MACRO-BODY ...)) 215 | } 216 | 217 | \index{Kawa} 218 | \index{SCM} 219 | 220 | \n In SCM~\cite{scm} and Kawa \cite{kawa}: 221 | 222 | \q{ 223 | (defmacro MACRO-NAME MACRO-ARGS 224 | MACRO-BODY ...) 225 | } 226 | 227 | \index{STk} 228 | 229 | \n In STk~\cite{stk}: 230 | 231 | \q{ 232 | (define-macro (MACRO-NAME . MACRO-ARGS) 233 | MACRO-BODY ...) 234 | } 235 | 236 | \index{load-relative@\q{load-relative}!in various dialects} 237 | 238 | \section{\q{load-relative}} 239 | 240 | The procedure \q{load-relative} may be defined for Guile as follows: 241 | 242 | \q{ 243 | (define load-relative 244 | (lambda (f) 245 | (let* ((n (string-length f)) 246 | (full-pathname? 247 | (and (> n 0) 248 | (let ((c0 (string-ref f 0))) 249 | (or (char=? c0 #\/) 250 | (char=? c0 #\~)))))) 251 | (basic-load 252 | (if full-pathname? f 253 | (let ((clp (current-load-port))) 254 | (if clp 255 | (string-append 256 | (dirname (port-filename clp)) "/" f) 257 | f))))))) 258 | } 259 | 260 | For SCM: 261 | 262 | \q{ 263 | (define load-relative 264 | (lambda (f) 265 | (let* ((n (string-length f)) 266 | (full-pathname? 267 | (and (> n 0) 268 | (let ((c0 (string-ref f 0))) 269 | (or (char=? c0 #\/) 270 | (char=? c0 #\~)))))) 271 | (load (if (and *load-pathname* full-pathname?) 272 | (in-vicinity (program-vicinity) f) 273 | f))))) 274 | } 275 | 276 | For STk, the following definition for \q{load-relative} 277 | works only if you discipline yourself to not use \q{load}: 278 | 279 | \q{ 280 | (define *load-pathname* #f) 281 | 282 | (define stk%load load) 283 | 284 | (define load-relative 285 | (lambda (f) 286 | (fluid-let 287 | ((*load-pathname* 288 | (if (not *load-pathname*) f 289 | (let* ((n (string-length f)) 290 | (full-pathname? 291 | (and (> n 0) 292 | (let ((c0 (string-ref f 0))) 293 | (or (char=? c0 #\/) 294 | (char=? c0 #\~)))))) 295 | (if full-pathname? f 296 | (string-append 297 | (dirname *load-pathname*) 298 | "/" f)))))) 299 | (stk%load *load-pathname*)))) 300 | 301 | (define load 302 | (lambda (f) 303 | (error "Don’t use load. Use load-relative instead."))) 304 | } 305 | -------------------------------------------------------------------------------- /obj1.tex: -------------------------------------------------------------------------------- 1 | \scmfilename obj1.scm 2 | 3 | \scmwrite{ 4 | (load-relative "deldup.scm") 5 | (load-relative "defstruct.scm") 6 | } 7 | 8 | \section{A simple object system} 9 | 10 | \index{inheritance!single} 11 | Let us now implement a basic object system in Scheme. 12 | We will allow only one superclass per class ({\em 13 | single inheritance}). If we don’t want to specify a 14 | superclass, we will use \q{#t} as a “zero” 15 | superclass, one that has neither slots nor methods. 16 | The superclass of \q{#t} is deemed to be itself. 17 | 18 | As a first approximation, it is useful to define 19 | classes using a struct called \q{standard-class}, with 20 | fields for the slot names, the superclass, and the 21 | methods. The first two fields we will call \q{slots} 22 | and \q{superclass} respectively. We will use {\em two} 23 | fields for methods, a 24 | \q{method-names} field that will hold the list of names 25 | of the class’s methods, and a 26 | \q{method-vector} field that will hold the vector of 27 | the values of the class’s methods.\f{We could in theory 28 | define methods also as slots (whose values happen to be 29 | procedures), but there is a good reason not to. The 30 | instances of a class share methods but in general 31 | differ in their slot values. In other words, methods 32 | can be included in the class definition and don’t have 33 | to be allocated per instance as slots have to be.} 34 | Here is the definition of the \q{standard-class}: 35 | 36 | \scmdribble{ 37 | (defstruct standard-class 38 | slots superclass method-names method-vector) 39 | } 40 | 41 | \n We can use \q{make-standard-class}, the maker procedure of 42 | \q{standard-class}, to create a new class. E.g., 43 | 44 | \q{ 45 | (define trivial-bike-class 46 | (make-standard-class 47 | 'superclass #t 48 | 'slots '(frame parts size) 49 | 'method-names '() 50 | 'method-vector #())) 51 | } 52 | 53 | \n This is a very simple class. More complex classes 54 | will have non-trivial superclasses and methods, which 55 | will require a lot of standard initialization that we 56 | would like to hide within the class creation process. 57 | We will therefore define a macro called 58 | \q{create-class} that will make the appropriate call to 59 | \q{make-standard-class}. 60 | 61 | \scmdribble{ 62 | (define-macro create-class 63 | (lambda (superclass slots . methods) 64 | `(create-class-proc 65 | ,superclass 66 | (list ,@(map (lambda (slot) `',slot) slots)) 67 | (list ,@(map (lambda (method) `',(car method)) methods)) 68 | (vector ,@(map (lambda (method) `,(cadr method)) methods))))) 69 | } 70 | 71 | \n We will defer the definition of the 72 | \q{create-class-proc} procedure to later. 73 | 74 | The procedure \q{make-instance} creates an {\em 75 | instance} of a class by generating a fresh vector based 76 | on information enshrined in the class. The format of 77 | the instance vector is very simple: Its first element 78 | will refer to the class, and its remaining elements 79 | will be slot values. \q{make-instance}’s arguments are 80 | the class followed by a sequence of twosomes, where 81 | each twosome is a slot name and the value it assumes in 82 | the instance. 83 | 84 | \scmdribble{ 85 | (define make-instance 86 | (lambda (class . slot-value-twosomes) 87 | 88 | ;Find ‘n’, the number of slots in ‘class’. 89 | ;Create an instance vector of length ‘n + 1’, 90 | ;because we need one extra element in the instance 91 | ;to contain the class. 92 | 93 | (let* ((slotlist (standard-class.slots class)) 94 | (n (length slotlist)) 95 | (instance (make-vector (+ n 1)))) 96 | (vector-set! instance 0 class) 97 | 98 | ;Fill each of the slots in the instance 99 | ;with the value as specified in the call to 100 | ;‘make-instance’. 101 | 102 | (let loop ((slot-value-twosomes slot-value-twosomes)) 103 | (if (null? slot-value-twosomes) instance 104 | (let ((k (list-position (car slot-value-twosomes) 105 | slotlist))) 106 | (vector-set! instance (+ k 1) 107 | (cadr slot-value-twosomes)) 108 | (loop (cddr slot-value-twosomes)))))))) 109 | } 110 | 111 | \n Here is an example of instantiating a class: 112 | 113 | \q{ 114 | (define my-bike 115 | (make-instance trivial-bike-class 116 | 'frame 'cromoly 117 | 'size '18.5 118 | 'parts 'alivio)) 119 | } 120 | 121 | \n This binds \q{my-bike} to the instance 122 | 123 | \q{ 124 | #( cromoly 18.5 alivio) 125 | } 126 | 127 | \n where \q{} is a Scheme datum (another 128 | vector) that is the value of \q{trivial-bike-class}, as defined 129 | above. 130 | 131 | The procedure \q{class-of} returns the class of an instance: 132 | 133 | \q{ 134 | (define class-of 135 | (lambda (instance) 136 | (vector-ref instance 0))) 137 | } 138 | 139 | \n This assumes that \q{class-of}’s argument will be a class 140 | instance, i.e., a vector whose first element points to some 141 | instantiation of the \q{standard-class}. 142 | We probably want to make \q{class-of} return an appropriate value 143 | for any kind of Scheme object we feed to it. 144 | 145 | \scmdribble{ 146 | (define class-of 147 | (lambda (x) 148 | (if (vector? x) 149 | (let ((n (vector-length x))) 150 | (if (>= n 1) 151 | (let ((c (vector-ref x 0))) 152 | (if (standard-class? c) c #t)) 153 | #t)) 154 | #t))) 155 | } 156 | 157 | \n The class of a Scheme object that isn’t created 158 | using \q{standard-class} is deemed to be \q{#t}, the 159 | zero class. 160 | 161 | The procedures \q{slot-value} and \q{set!slot-value} 162 | access and mutate the values of a class instance: 163 | 164 | \scmdribble{ 165 | (define slot-value 166 | (lambda (instance slot) 167 | (let* ((class (class-of instance)) 168 | (slot-index 169 | (list-position slot (standard-class.slots class)))) 170 | (vector-ref instance (+ slot-index 1))))) 171 | 172 | (define set!slot-value 173 | (lambda (instance slot new-val) 174 | (let* ((class (class-of instance)) 175 | (slot-index 176 | (list-position slot (standard-class.slots class)))) 177 | (vector-set! instance (+ slot-index 1) new-val)))) 178 | } 179 | 180 | \n We are now ready to tackle the definition of 181 | \q{create-class-proc}. This procedure takes a 182 | superclass, a list of slots, a list of method names, 183 | and a vector of methods and makes the appropriate call 184 | to \q{make-standard-class}. The only tricky part is 185 | the value to be given to the \q{slots} field. It can’t 186 | be just the slots argument supplied via 187 | \q{create-class}, for a class must include the slots of 188 | its superclass as well. We must append the supplied 189 | slots to the superclass’s slots, making sure that we 190 | don’t have duplicate slots. 191 | 192 | \scmdribble{ 193 | (define create-class-proc 194 | (lambda (superclass slots method-names method-vector) 195 | (make-standard-class 196 | 'superclass superclass 197 | 'slots 198 | (let ((superclass-slots 199 | (if (not (eqv? superclass #t)) 200 | (standard-class.slots superclass) 201 | '()))) 202 | (if (null? superclass-slots) slots 203 | (delete-duplicates 204 | (append slots superclass-slots)))) 205 | 'method-names method-names 206 | 'method-vector method-vector))) 207 | } 208 | 209 | \index{delete-duplicates@\q{delete-duplicates}} 210 | \n The procedure \q{delete-duplicates} called on a list 211 | \q{s}, returns a new list that only includes the {\em last} 212 | occurrence of each element of \q{s}. 213 | 214 | \q{ 215 | (define delete-duplicates 216 | (lambda (s) 217 | (if (null? s) s 218 | (let ((a (car s)) (d (cdr s))) 219 | (if (memv a d) (delete-duplicates d) 220 | (cons a (delete-duplicates d))))))) 221 | } 222 | 223 | Now to the application of methods. We invoke the 224 | method on an instance by using the procedure \q{send}. 225 | \q{send}’s arguments are the method name, followed by 226 | the instance, followed by any arguments the method has 227 | in addition to the instance itself. Since methods are 228 | stored in the instance’s class instead of the instance 229 | itself, \q{send} will search the instance’s class for 230 | the method. If the method is not found there, it is 231 | looked for in the class’s superclass, and so on further 232 | up the superclass chain: 233 | 234 | \scmdribble{ 235 | (define send 236 | (lambda (method instance . args) 237 | (let ((proc 238 | (let loop ((class (class-of instance))) 239 | (if (eqv? class #t) (error 'send) 240 | (let ((k (list-position 241 | method 242 | (standard-class.method-names class)))) 243 | (if k 244 | (vector-ref (standard-class.method-vector class) k) 245 | (loop (standard-class.superclass class)))))))) 246 | (apply proc instance args)))) 247 | } 248 | 249 | We can now define some more interesting classes: 250 | 251 | \scmfilename bike.scm 252 | 253 | \scmdribble{ 254 | (define bike-class 255 | (create-class 256 | #t 257 | (frame size parts chain tires) 258 | (check-fit (lambda (me inseam) 259 | (let ((bike-size (slot-value me 'size)) 260 | (ideal-size (* inseam 3/5))) 261 | (let ((diff (- bike-size ideal-size))) 262 | (cond ((<= -1 diff 1) 'perfect-fit) 263 | ((<= -2 diff 2) 'fits-well) 264 | ((< diff -2) 'too-small) 265 | ((> diff 2) 'too-big)))))))) 266 | } 267 | 268 | \n Here, \q{bike-class} includes a method \q{check-fit}, that 269 | takes a bike and an inseam measurement and reports on 270 | the fit of the bike for a person of that inseam. 271 | 272 | Let’s redefine \q{my-bike}: 273 | 274 | \scmdribble{ 275 | (define my-bike 276 | (make-instance bike-class 277 | 'frame 'titanium ; I wish 278 | 'size 21 279 | 'parts 'ultegra 280 | 'chain 'sachs 281 | 'tires 'continental)) 282 | } 283 | 284 | To check if this will fit someone with inseam 32: 285 | 286 | \q{ 287 | (send 'check-fit my-bike 32) 288 | } 289 | 290 | We can subclass \q{bike-class}. 291 | 292 | \scmdribble{ 293 | (define mtn-bike-class 294 | (create-class 295 | bike-class 296 | (suspension) 297 | (check-fit (lambda (me inseam) 298 | (let ((bike-size (slot-value me 'size)) 299 | (ideal-size (- (* inseam 3/5) 2))) 300 | (let ((diff (- bike-size ideal-size))) 301 | (cond ((<= -2 diff 2) 'perfect-fit) 302 | ((<= -4 diff 4) 'fits-well) 303 | ((< diff -4) 'too-small) 304 | ((> diff 4) 'too-big)))))))) 305 | } 306 | 307 | \n \q{mtn-bike-class} adds a slot called \q{suspension} 308 | and uses a slightly different definition for the method 309 | \q{check-fit}. 310 | 311 | \scmfilename deldup.scm 312 | 313 | \scmwrite{ 314 | (define delete-duplicates 315 | (lambda (s) 316 | (if (null? s) s 317 | (let ((a (car s)) (d (cdr s))) 318 | (if (memv a d) (delete-duplicates d) 319 | (cons a (delete-duplicates d))))))) 320 | } 321 | 322 | -------------------------------------------------------------------------------- /macro.tex: -------------------------------------------------------------------------------- 1 | \scmkeyword{my-or} 2 | 3 | \chapter{Macros} 4 | \label{sugar} 5 | 6 | \index{macro} 7 | Users can create their own special forms by defining 8 | {\em macros}. A macro is a symbol that has a {\em 9 | transformer procedure} associated with it. When Scheme 10 | encounters a macro-expression — i.e., a form whose 11 | head is a macro —, it applies the macro’s transformer 12 | to the subforms in the macro-expression, and evaluates 13 | the result of the transformation. 14 | 15 | Ideally, a macro specifies a purely textual 16 | transformation from code text to other code text. This 17 | kind of transformation is useful for abbreviating an 18 | involved and perhaps frequently occurring textual 19 | pattern. 20 | 21 | \scmkeyword{proc} 22 | 23 | \index{define-macro@\q{define-macro}} 24 | \index{when@\q{when}!macro for} 25 | 26 | A macro is {\em defined} using the special form 27 | \q{define-macro} (but see 28 | section~\ref{dialect-macro}).\f{MzScheme provides 29 | \q{define-macro} via the \p{defmacro} library. Use \q{(require (lib 30 | "defmacro.ss"))} to load this library.} 31 | For example, if your Scheme lacks the conditional 32 | special form \q{when}, you could define 33 | \q{when} as the following macro: 34 | 35 | \q{ 36 | (define-macro when 37 | (lambda (test . branch) 38 | (list 'if test 39 | (cons 'begin branch)))) 40 | } 41 | 42 | 43 | \n This defines a \q{when}-transformer that would 44 | convert a \q{when}-expression into the equivalent 45 | \q{if}-expression. With this macro definition in 46 | place, the \q{when}-expression 47 | 48 | \q{ 49 | (when (< (pressure tube) 60) 50 | (open-valve tube) 51 | (attach floor-pump tube) 52 | (depress floor-pump 5) 53 | (detach floor-pump tube) 54 | (close-valve tube)) 55 | } 56 | 57 | \n will be converted to another expression, the result 58 | of applying the 59 | \q{when}-transformer to the \q{when}-expression’s 60 | subforms: 61 | 62 | \q{ 63 | (apply 64 | (lambda (test . branch) 65 | (list 'if test 66 | (cons 'begin branch))) 67 | '((< (pressure tube) 60) 68 | (open-valve tube) 69 | (attach floor-pump tube) 70 | (depress floor-pump 5) 71 | (detach floor-pump tube) 72 | (close-valve tube))) 73 | } 74 | 75 | \n The transformation yields the list 76 | 77 | \q{ 78 | (if (< (pressure tube) 60) 79 | (begin 80 | (open-valve tube) 81 | (attach floor-pump tube) 82 | (depress floor-pump 5) 83 | (detach floor-pump tube) 84 | (close-valve tube))) 85 | } 86 | 87 | \n Scheme will then evaluate this expression, as it 88 | would any other. 89 | 90 | \index{unless@\q{unless}!macro for} 91 | 92 | As an additional example, here is the macro-definition 93 | for \q{when}’s counterpart \q{unless}: 94 | 95 | \q{ 96 | (define-macro unless 97 | (lambda (test . branch) 98 | (list 'if 99 | (list 'not test) 100 | (cons 'begin branch)))) 101 | } 102 | 103 | \n Alternatively, we could invoke \q{when} inside 104 | \q{unless}’s definition: 105 | 106 | \q{ 107 | (define-macro unless 108 | (lambda (test . branch) 109 | (cons 'when 110 | (cons (list 'not test) branch)))) 111 | } 112 | 113 | \n Macro expansions can refer to other macros. 114 | 115 | \section{Specifying the expansion as a template} 116 | 117 | A macro transformer takes some s-expressions and 118 | produces an s-expression that will be used as a form. 119 | Typically this output is a list. In our 120 | \q{when} example, the output list is created using 121 | 122 | \q{ 123 | (list 'if test 124 | (cons 'begin branch)) 125 | } 126 | 127 | \n where \q{test} is bound to the macro’s first 128 | subform, i.e., 129 | 130 | \q{ 131 | (< (pressure tube) 60) 132 | } 133 | 134 | \n and \q{branch} to the rest of the macro’s subforms, 135 | i.e., 136 | 137 | \q{ 138 | ((open-valve tube) 139 | (attach floor-pump tube) 140 | (depress floor-pump 5) 141 | (detach floor-pump tube) 142 | (close-valve tube)) 143 | } 144 | 145 | \index{`@\q{`} (backquote)} 146 | \index{,@\q{,} (comma)} 147 | \index{,"@@\q{,"@} (comma-splice)} 148 | 149 | \n 150 | Output lists can be quite complicated. It is easy to 151 | see that a more ambitious macro than \q{when} could 152 | lead to quite an elaborate construction process for the 153 | output list. In such cases, it is more convenient to 154 | specify the macro’s output form as a {\em template}, 155 | with the macro arguments inserted at appropriate places 156 | to fill out the template for each particular use of the 157 | macro. Scheme provides the {\em backquote} syntax to 158 | specify such templates. Thus the expression 159 | 160 | \q{ 161 | (list 'IF test 162 | (cons 'BEGIN branch)) 163 | } 164 | 165 | \n is more conveniently written as 166 | 167 | \q{ 168 | `(IF ,test 169 | (BEGIN ,@branch)) 170 | } 171 | 172 | \n We can refashion the \q{when} macro-definition as: 173 | 174 | \q{ 175 | (define-macro when 176 | (lambda (test . branch) 177 | `(IF ,test 178 | (BEGIN ,@branch)))) 179 | } 180 | 181 | \n Note that the template format, unlike the earlier 182 | list construction, gives immediate visual indication of 183 | the shape of the output list. The backquote (\q{`}) 184 | introduces a template for a list. The elements of the 185 | template appear {\em verbatim} in the resulting list, 186 | {\em except} when they are prefixed by a {\em comma} 187 | (‘\q{,}’) or a {\em comma-splice} (‘\q{,@}’). (For the 188 | purpose of illustration, we have written the verbatim 189 | elements of the template in UPPER-CASE.) 190 | 191 | The comma and the comma-splice are used to insert the 192 | macro arguments into the template. The comma inserts 193 | the result of evaluating its following expression. The 194 | comma-splice inserts the result of evaluating its 195 | following expression after {\em splicing} it, i.e., it 196 | removes the outermost set of parentheses. (This 197 | implies that an expression introduced by comma-splice 198 | {\em must} be a list.) 199 | 200 | In our example, given the values that \q{test} and 201 | \q{branch} are bound to, it is easy to see that the 202 | template will expand to the required 203 | 204 | \q{ 205 | (IF (< (pressure tube) 60) 206 | (BEGIN 207 | (open-valve tube) 208 | (attach floor-pump tube) 209 | (depress floor-pump 5) 210 | (detach floor-pump tube) 211 | (close-valve tube))) 212 | } 213 | 214 | \section{Avoiding variable capture inside macros} 215 | 216 | \index{macro!avoiding variable capture inside} 217 | A two-argument disjunction form, \q{my-or}, could be 218 | defined as follows: 219 | 220 | \q{ 221 | (define-macro my-or 222 | (lambda (x y) 223 | `(if ,x ,x ,y))) 224 | } 225 | 226 | \n 227 | \q{my-or} takes two arguments and returns the value of 228 | the first of them that is true (i.e., non-\q{#f}). In 229 | particular, the second argument is evaluated only if 230 | the first turns out to be false. 231 | 232 | \q{ 233 | (my-or 1 2) 234 | |evalsto 1 235 | 236 | (my-or #f 2) 237 | |evalsto 2 238 | } 239 | 240 | There is a problem with the \q{my-or} macro as it is 241 | written. It re-evaluates the first argument if it is 242 | true: once in the \q{if}-test, and once again in the 243 | “then” branch. This can cause undesired behavior if 244 | the first argument were to contain side-effects, e.g., 245 | 246 | \q{ 247 | (my-or 248 | (begin 249 | (display "doing first argument") 250 | (newline) 251 | #t) 252 | 2) 253 | } 254 | 255 | \n displays \q{"doing first argument"} twice. 256 | 257 | This can be avoided by storing 258 | the \q{if}-test result in a local variable: 259 | 260 | \q{ 261 | (define-macro my-or 262 | (lambda (x y) 263 | `(let ((temp ,x)) 264 | (if temp temp ,y)))) 265 | } 266 | 267 | \n This is almost OK, except in the case where the 268 | second argument happens to contain the same 269 | identifier \q{temp} as used in the macro definition. 270 | E.g., 271 | 272 | \q{ 273 | (define temp 3) 274 | 275 | (my-or #f temp) 276 | |evalsto #f 277 | } 278 | 279 | \n Surely it should be 3! The fiasco happens because 280 | the macro uses a local variable \q{temp} to store the 281 | value of the first argument (\q{#f}) and the 282 | variable 283 | \q{temp} in the second argument got {\em captured} by 284 | the 285 | \q{temp} introduced by the macro. 286 | 287 | To avoid this, we need to be careful in choosing local 288 | variables inside macro definitions. We could choose 289 | outlandish names for such variables and hope fervently 290 | that nobody else comes up with them. E.g., 291 | 292 | \q{ 293 | (define-macro my-or 294 | (lambda (x y) 295 | `(let ((+temp ,x)) 296 | (if +temp +temp ,y)))) 297 | } 298 | 299 | \n This will work given the tacit understanding 300 | that \q{+temp} will not be used by code outside the 301 | macro. This is of course an understanding waiting to 302 | be disillusioned. 303 | 304 | \index{gensym@\q{gensym}} 305 | \index{symbol!generated} 306 | 307 | A more reliable, if verbose, approach is to use {\em 308 | generated symbols} that are guaranteed not to be 309 | obtainable by other means. The procedure \q{gensym} 310 | generates unique symbols each time it is called. Here 311 | is a safe definition for \q{my-or} using \q{gensym}: 312 | 313 | \q{ 314 | (define-macro my-or 315 | (lambda (x y) 316 | (let ((temp (gensym))) 317 | `(let ((,temp ,x)) 318 | (if ,temp ,temp ,y))))) 319 | } 320 | 321 | \n In the macros defined in this document, in order to be 322 | concise, we will not use the \q{gensym} approach. 323 | Instead, we will consider the point about variable 324 | capture as having been made, and go ahead with the less 325 | cluttered \q{+}-as-prefix approach. We will leave it 326 | to the astute reader to remember to convert these 327 | \q{+}-identifiers into gensyms in the manner outlined 328 | above. 329 | 330 | \index{fluid-let@\q{fluid-let}!macro for} 331 | 332 | \section{\q{fluid-let}} 333 | \label{fluid-let-macro} 334 | 335 | Here is a definition of a rather more complicated 336 | macro, \q{fluid-let} (section~\ref{fluid-let}). 337 | \q{fluid-let} specifies temporary bindings for 338 | a set of already existing lexical variables. Given a 339 | \q{fluid-let} expression such as 340 | 341 | \q{ 342 | (fluid-let ((x 9) (y (+ y 1))) 343 | (+ x y)) 344 | } 345 | 346 | \n we want the expansion to be 347 | 348 | \q{ 349 | (let ((OLD-X x) (OLD-Y y)) 350 | (set! x 9) 351 | (set! y (+ y 1)) 352 | (let ((RESULT (begin (+ x y)))) 353 | (set! x OLD-X) 354 | (set! y OLD-Y) 355 | RESULT)) 356 | } 357 | 358 | \n where we want the identifiers \q{OLD-X}, \q{OLD-Y}, 359 | and \q{RESULT} to be symbols that will not capture 360 | variables in the expressions in the \q{fluid-let} form. 361 | 362 | Here is how we go about fashioning a \q{fluid-let} 363 | macro that implements what we want: 364 | 365 | \q{ 366 | (define-macro fluid-let 367 | (lambda (xexe . body) 368 | (let ((xx (map car xexe)) 369 | (ee (map cadr xexe)) 370 | (old-xx (map (lambda (ig) (gensym)) xexe)) 371 | (result (gensym))) 372 | `(let ,(map (lambda (old-x x) `(,old-x ,x)) 373 | old-xx xx) 374 | ,@(map (lambda (x e) 375 | `(set! ,x ,e)) 376 | xx ee) 377 | (let ((,result (begin ,@body))) 378 | ,@(map (lambda (x old-x) 379 | `(set! ,x ,old-x)) 380 | xx old-xx) 381 | ,result))))) 382 | } 383 | 384 | \n The macro’s arguments are: 385 | \q{xexe}, the list of 386 | variable/expression pairs introduced by the \q{fluid-let}; and 387 | \q{body}, the list of 388 | expressions in the body of the \q{fluid-let}. In our 389 | example, these are \q{((x 9) (y (+ y 1)))} and \q{((+ x 390 | y))} respectively. 391 | 392 | The macro body introduces a bunch of local variables: 393 | \q{xx} is the list of the variables extracted from the 394 | variable/expression pairs. 395 | \q{ee} is the corresponding list of 396 | expressions. \q{old-xx} is a list of fresh identifiers, 397 | one for each variable in \q{xx}. These are used to 398 | store the {\em incoming} values of the \q{xx}, so we 399 | can revert the \q{xx} back to them once the 400 | \q{fluid-let} body has been evaluated. 401 | \q{result} is another 402 | fresh identifier, used to store the value of the 403 | \q{fluid-let} body. In our example, \q{xx} is \q{(x y)} 404 | and \q{ee} is \q{(9 (+ y 1))}. Depending on how your 405 | system implements \q{gensym}, 406 | \q{old-xx} might be the 407 | list \q{(GEN-63 GEN-64)}, and \q{result} might be \q{GEN-65}. 408 | 409 | The output list is created by the macro for our given 410 | example looks like 411 | 412 | \q{ 413 | (let ((GEN-63 x) (GEN-64 y)) 414 | (set! x 9) 415 | (set! y (+ y 1)) 416 | (let ((GEN-65 (begin (+ x y)))) 417 | (set! x GEN-63) 418 | (set! y GEN-64) 419 | GEN-65)) 420 | } 421 | 422 | \n 423 | which matches our requirement. 424 | 425 | -------------------------------------------------------------------------------- /engine.tex: -------------------------------------------------------------------------------- 1 | \chapter{Engines} 2 | 3 | \index{engine} 4 | An engine \cite{engine} represents computation that is 5 | subject to timed preemption. In other words, an 6 | engine’s underlying computation is an ordinary thunk 7 | that runs as a timer-preemptable process. 8 | 9 | An engine is called with three arguments: (1) a number 10 | of time units or {\em ticks}, (2) a {\em success} 11 | procedure, and (3) a {\em failure} procedure. If the 12 | engine computation finishes within the allotted {\em 13 | ticks}, the {\em success} procedure is applied to the 14 | computation result and the remaining ticks. If the 15 | engine computation could not finish within the allotted 16 | {\em ticks}, the {\em failure} procedure is applied 17 | to a new engine representing the unfinished portion of 18 | the engine computation. 19 | 20 | For example, consider an engine whose underlying 21 | computation is a loop that printed the nonnegative 22 | integers in sequence. It is created as follows, with 23 | the soon-to-be-defined \q{make-engine} procedure. 24 | \q{make-engine} is called on an argument thunk 25 | representing the underlying computation, and it 26 | returns the corresponding engine: 27 | 28 | \q{ 29 | (define printn-engine 30 | (make-engine 31 | (lambda () 32 | (let loop ((i 0)) 33 | (display i) 34 | (display " ") 35 | (loop (+ i 1)))))) 36 | } 37 | 38 | \n Here is a call to \q{printn-engine}: 39 | 40 | \q{ 41 | (define *more* #f) 42 | (printn-engine 50 list (lambda (ne) (set! *more* ne))) 43 | |evalsto 0 1 2 3 4 5 6 7 8 9 44 | } 45 | 46 | \n I.e., the loop gets to print upto a certain number 47 | (here \q{9}) and then fails because of the clock 48 | interrupt. However, our {\em failure} procedure sets 49 | a global variable called \q{*more*} to the failed 50 | engine, which we can use to resume the loop where the 51 | previous engine left off: 52 | 53 | \q{ 54 | (*more* 50 list (lambda (ne) (set! *more* ne))) 55 | |evalsto 10 11 12 13 14 15 16 17 18 19 56 | } 57 | 58 | \index{call/cc@\q{call/cc}!and engine} 59 | 60 | We will now construct engines using \q{call/cc} to 61 | capture the unfinished computation of a failing engine. 62 | First we will construct {\em flat} engines, or 63 | engines whose computation cannot include the running of 64 | other engines. We will later generalize the code to 65 | the more general {\em nestable} engines or {\em 66 | nesters}, which can call other engines. But in both 67 | cases, we need a timer mechanism, or a {\em clock}. 68 | 69 | \index{clock} 70 | 71 | \section{The clock} 72 | \label{engine-clock} 73 | 74 | Our engines assume the presence of a global clock or 75 | interruptable timer that marks the passage of ticks as 76 | a program executes. We will assume the following clock 77 | interface — if your Scheme provides any kind of alarm 78 | mechanism, it should be an easy matter to rig up a 79 | clock of the following type. (Appendix~\ref{clock} 80 | defines a clock for the Guile~\cite{guile} dialect of 81 | Scheme.) 82 | 83 | The internal state of our \q{clock} procedure consists 84 | of two items: 85 | 86 | (1) the number of remaining ticks; and 87 | 88 | (2) an interrupt handler to be invoked when the 89 | clock runs out of ticks. 90 | 91 | \q{clock} allows the following operations: 92 | 93 | (1) \q{(clock 'set-handler h)} sets the 94 | interrupt handler to \q{h}. 95 | 96 | (2) \q{(clock 'set n)} resets the clock’s 97 | remaining ticks to \q{n}, returning the 98 | previous value. 99 | 100 | The number of ticks ranges over the non-negative 101 | integers and an atom called \q{*infinity*}. A clock with 102 | \q{*infinity*} ticks cannot run out of time and so will 103 | not set off the interrupt handler. Such a clock is 104 | {\em quiescent} or “already stopped”. To stop a 105 | clock, set its ticks to \q{*infinity*}. 106 | 107 | The clock handler is set to a thunk. For example, 108 | 109 | \q{ 110 | (clock 'set-handler 111 | (lambda () 112 | (error "Say goodnight, cat!"))) 113 | 114 | (clock 'set 9) 115 | } 116 | 117 | \n This will cause an error to be signaled after 9 118 | ticks have passed, and the message displayed by the 119 | signal will be “Say goodnight, cat!” 120 | 121 | \index{engine!flat} 122 | \section{Flat engines} 123 | 124 | We will first set the clock interrupt handler. Note 125 | that the handler is invoked only if a non-quiescent 126 | clock runs out of ticks. This happens only during 127 | engine computations that are on the brink of failure, 128 | for only engines set the clock. 129 | 130 | The handler captures the current continuation, which is 131 | the rest of the computation of the currently failing 132 | engine. This continuation is sent to another 133 | continuation stored in the global \q{*engine-escape*}. 134 | The \q{*engine-escape*} variable stores the exit 135 | continuation of the current engine. Thus the clock 136 | handler captures the rest of the failing engine and 137 | sends it to an exit point in the engine code, so the 138 | requisite failure action can be taken. 139 | 140 | \scmfilename engine.scm 141 | 142 | \scmdribble{ 143 | (define *engine-escape* #f) 144 | (define *engine-entrance* #f) 145 | 146 | (clock 'set-handler 147 | (lambda () 148 | (call/cc *engine-escape*))) 149 | } 150 | 151 | Let us now look into the innards of the engine code 152 | itself. As said, \q{make-engine} takes a thunk and 153 | fashions an engine out of it: 154 | 155 | \scmdribble{ 156 | (define make-engine 157 | (lambda (th) 158 | (lambda (ticks success failure) 159 | (let* ((ticks-left 0) 160 | (engine-succeeded? #f) 161 | (result 162 | (call/cc 163 | (lambda (k) 164 | (set! *engine-escape* k) 165 | (let ((result 166 | (call/cc 167 | (lambda (k) 168 | (set! *engine-entrance* k) 169 | (clock 'set ticks) 170 | (let ((v (th))) 171 | (*engine-entrance* v)))))) 172 | (set! ticks-left (clock 'set *infinity*)) 173 | (set! engine-succeeded? #t) 174 | result))))) 175 | (if engine-succeeded? 176 | (success result ticks-left) 177 | (failure 178 | (make-engine 179 | (lambda () 180 | (result 'resume))))))))) 181 | } 182 | 183 | \n First we introduce the variables \q{ticks-left} 184 | and \q{engine-succeeded?}. The first will hold 185 | the ticks left over should the engine thunk finish 186 | in time. The second is a flag that will be used in 187 | the engine code to signal if the engine suceeded. 188 | 189 | We then run the engine thunk within two nested calls to 190 | \q{call/cc}. The first \q{call/cc} captures the 191 | continuation to be used by a failing engine to abort 192 | out of its engine computation. This continuation is 193 | stored in the global \q{*engine-escape*}. The second 194 | \q{call/cc} captures an inner continuation that 195 | will be used by the return value of the thunk \q{th} if 196 | it runs to completion. This continuation is stored 197 | in the global 198 | \q{*engine-entrance*}. 199 | 200 | Running through the code, we find that after capturing 201 | the continuations \q{*engine-escape*} and 202 | \q{*engine-entrance*}, we set the clock’s ticks to the 203 | time allotted this engine and run the thunk \q{th}. If 204 | \q{th} succeeds, its value \q{v} is sent to the 205 | continuation \q{*engine-entrance*}, after which the 206 | clock is stopped, the remaining ticks ascertained, and 207 | the flag \q{engine-succeeded?} is set to true. We now 208 | go past the \q{*engine-escape*} continuation, and run 209 | the final dispatcher in the code: Since we know the 210 | engine succeeded, we apply the \q{success} procedure to 211 | the result and the ticks left. 212 | 213 | If the thunk \q{th} {\em didn’t} finish in time 214 | though, it will suffer an interrupt. This invokes the 215 | clock interrupt handler, which captures the current 216 | continuation of the running and now failing thunk and 217 | sends it to the continuation \q{*engine-escape*}. This 218 | puts the failed-thunk continuation in the outer 219 | \q{result} variable, and we are now in the final 220 | dispatcher in the code: Since \q{engine-succeeded?} is 221 | still false, we apply the \q{failure} procedure to new 222 | engine fashioned out of \q{result}. 223 | 224 | Notice that when a failed engine is removed, it will 225 | traverse the control path charted by the first run of 226 | the original engine. Nevertheless, because we have 227 | explicitly use the continuations stored in the global 228 | variables \q{*engine-entrance*} and 229 | \q{*engine-escape*}, and we always set them anew before 230 | executing an engine computation, we are assured that 231 | the jumps will always come back to the currently 232 | executing engine code. 233 | 234 | \index{engine!nestable} 235 | \section{Nestable engines} 236 | 237 | In order to generalize the code above to accommodate 238 | the nestable type of engine, we need to incorporate 239 | into it some {\em tick management} that will take 240 | care of the apportioning of the right amounts of ticks 241 | to all the engines in a nested run. 242 | 243 | To run a new engine (the {\em child}), we need to 244 | stop the currently engine (the {\em parent}). We 245 | then need to assign an appropriate number of ticks to 246 | the child. This may not be the same as the ticks 247 | assigned by the program text, because it would be {\em 248 | unfair} for a child to consume more ticks than its 249 | parent has left. After the child completes, we need to 250 | update the parent’s ticks. If the child finished in 251 | time, any leftover ticks it has revert to the parent. 252 | If ticks were denied from the child because the parent 253 | couldn’t afford it, then if the child fails, the parent 254 | will fail too, but must remember to restart the child 255 | with its promised ticks when it (the parent) restarts. 256 | 257 | We also need to \q{fluid-let} the globals 258 | \q{*engine-escape*} and \q{*engine-entrance*}, because 259 | each nested engine must have its own pair of these 260 | sentinel continuations. As an engine exits (whether 261 | through success or failure), the \q{fluid-let} will 262 | ensure that the next enclosing engine’s sentinels take 263 | over. 264 | 265 | Combining all this, the code for nestable engines looks 266 | as follows: 267 | 268 | \scmfilename nestable-engine.scm 269 | \scmdribble{ 270 | (define make-engine 271 | (lambda (th) 272 | (lambda (ticks s f) 273 | (let* ((parent-ticks 274 | (clock 'set *infinity*)) 275 | 276 | ;A child can’t have more ticks than its parent’s 277 | ;remaining ticks 278 | (child-available-ticks 279 | (clock-min parent-ticks ticks)) 280 | 281 | ;A child’s ticks must be counted against the 282 | ;parent too 283 | (parent-ticks-left 284 | (clock-minus parent-ticks child-available-ticks)) 285 | 286 | ;If child was promised more ticks than parent 287 | ;could afford, remember how much it was 288 | ;short-changed by 289 | (child-ticks-left 290 | (clock-minus ticks child-available-ticks)) 291 | 292 | ;Used below to store ticks left in clock 293 | ;if child completes in time 294 | (ticks-left 0) 295 | 296 | (engine-succeeded? #f) 297 | 298 | (result 299 | (fluid-let ((*engine-escape* #f) 300 | (*engine-entrance* #f)) 301 | (call/cc 302 | (lambda (k) 303 | (set! *engine-escape* k) 304 | (let ((result 305 | (call/cc 306 | (lambda (k) 307 | (set! *engine-entrance* k) 308 | (clock 'set 309 | child-available-ticks) 310 | 311 | (let ((v (th))) 312 | 313 | (*engine-entrance* v)))))) 314 | (set! ticks-left 315 | (let ((n (clock 'set *infinity*))) 316 | (if (eqv? n *infinity*) 0 n))) 317 | (set! engine-succeeded? #t) 318 | result)))))) 319 | 320 | ;Parent can reclaim ticks that child didn’t need 321 | (set! parent-ticks-left 322 | (clock-plus parent-ticks-left ticks-left)) 323 | 324 | ;This is the true ticks that child has left — 325 | ;we include the ticks it was short-changed by 326 | (set! ticks-left 327 | (clock-plus child-ticks-left ticks-left)) 328 | 329 | ;Restart parent with its remaining ticks 330 | (clock 'set parent-ticks-left) 331 | ;The rest is now parent computation 332 | 333 | (cond 334 | ;Child finished in time — celebrate its success 335 | (engine-succeeded? (s result ticks-left)) 336 | 337 | ;Child failed because it ran out of promised time — 338 | ;call failure procedure 339 | ((= ticks-left 0) 340 | (f (make-engine (lambda () (result 'resume))))) 341 | 342 | ;Child failed because parent didn’t have enough time, 343 | ;i.e., parent failed too. If so, when parent is 344 | ;resumed, its first order of duty is to resume the 345 | ;child with its fair amount of ticks 346 | (else 347 | ((make-engine (lambda () (result 'resume))) 348 | ticks-left s f))))))) 349 | } 350 | 351 | Note that we have used the arithmetic operators 352 | \q{clock-min}, \q{clock-minus}, and \q{clock-plus} 353 | instead of \q{min}, \q{-}, and \q{+}. This is because 354 | the values used by the clock arithmetic includes 355 | \q{*infinity*} in addition to the integers. Some Scheme 356 | dialects provide an \q{*infinity*} value in their 357 | arithmetic\f{E.g., in Guile, you can \q{(define 358 | *infinity* (/ 1 0))}.} — if so, you can use the regular 359 | arithmetic operators. If not, it is an easy exercise 360 | to define the enhanced operators. 361 | 362 | -------------------------------------------------------------------------------- /numint.tex: -------------------------------------------------------------------------------- 1 | \chapter{Numerical techniques} 2 | \label{numint} 3 | 4 | \index{numerical integration} 5 | \index{Simpson’s rule} 6 | Recursion (including iteration) combines well with 7 | Scheme’s mathematical primitive procedures to implement 8 | various numerical techniques. As an example, 9 | let’s implement Simpson’s rule, a procedure for finding 10 | an approximation for a definite integral. 11 | 12 | \section{Simpson’s rule} 13 | 14 | The definite integral of a function $f(x)$ within an 15 | interval of integration $[a,b]$ can be viewed as the 16 | {\em area under the curve} representing $f(x)$ from the 17 | lower limit $x = a$ to the upper limit $x = b$. 18 | In other words, we consider the graph of the curve for 19 | $f(x)$ on the $x,y$-plane, and find the area enclosed 20 | between that curve, the $x$-axis, and the {\em 21 | ordinates} of $f(x)$ at $x = a$ and $x = b$. 22 | 23 | \verbwritefile numint.mp 24 | \verbwrite{ 25 | % File: numint.mp 26 | 27 | prologues := 3; 28 | outputformat := "eps"; 29 | outputtemplate := "%j-%c.%o"; 30 | 31 | beginfig(1); 32 | 33 | u = 1mm; 34 | 35 | x.max = 120u; 36 | y.max = 70u; 37 | 38 | % draw x- and y-axes 39 | drawarrow (-5u,0) -- (x.max,0); 40 | drawarrow (0,-5u) -- (0,y.max); 41 | 42 | % label the axes 43 | label.rt(btex $x$ etex, (x.max,0) shifted (5,0)); 44 | label.top(btex $y$ etex, (0,y.max) shifted (0,5)); 45 | 46 | x0 = 25u; 47 | 48 | % interval between x[i] and x[i+1] is h 49 | h = 5u; 50 | 51 | % number of intervals (minus 1) 52 | n = 14; 53 | 54 | % calculate all the x[i] 55 | for i = 1 upto n: 56 | x[i] = x0 + i*h; 57 | % drawdot(x[i],0); 58 | endfor; 59 | 60 | % specify a function f(x) that is defined 61 | % for all x in [ x0, x[n] ] 62 | path f; 63 | f = (x0-5u,40u) .. (x0+2h,55u) .. (x0+4h,65u) .. 64 | (x0+6h,55u) .. (x0+7h,55u) .. (x[n]+10u,50u); 65 | draw f; 66 | 67 | % label f(x) 68 | label.rt(btex $f(x)$ etex, point infinity of f); 69 | 70 | % x[i] is a good-looking abcissa in the middle 71 | % of [ x0, x[n] ] 72 | %i = 8; 73 | i = n div 2; 74 | 75 | path ord[]; 76 | 77 | % calculate (and draw) the ordinates for f(x) 78 | % at x0, x[i], x[i+1], x[n] 79 | for j = 0,i,i+1,n: 80 | z[j]f = ( (x[j],0)--(x[j],y.max) ) intersectionpoint f; 81 | ord[j] = (x[j],0) -- (x[j],y[j]f); 82 | draw ord[j]; 83 | endfor; 84 | 85 | %% gray the integral area 86 | %path integ; 87 | %integ = buildcycle(((x0-5,0)--(x[n]+5,0)), 88 | % ( (x0,-1) .. ord0 .. (x0,y0f+1)), f, 89 | %((x[n],-1) .. ord[n] .. (x[n], y[n]f+1))) ; 90 | %fill integ withcolor .8white; 91 | 92 | % identify x[i]--x[i+1] distance as h 93 | path hline; 94 | hline = (x[i],2h)--(x[i+1],2h); 95 | 96 | drawdblarrow hline; 97 | label.top(btex $h$ etex, point .5 of hline); 98 | 99 | % label the abcissae x0, x[i], x[i+1], x[n] 100 | 101 | dotlabel.bot(btex $\strut x_0 = a$ etex, (x0,0)); 102 | dotlabel.bot(btex $\strut x_i$ etex, (x[i],0)); 103 | dotlabel.lrt(btex $\strut x_{i+1}$ etex, (x[i+1],0)); 104 | dotlabel.bot(btex $\strut x_n = b$ etex, (x[n],0)); 105 | 106 | % label the corresponding ordinates 107 | label.lft(btex $y_0$ etex, point .5 of ord0); 108 | label.lft(btex $y_i$ etex, point .5 of ord[i]); 109 | label.rt(btex $y_{i+1}$ etex, point .5 of ord[i+1]); 110 | label.rt(btex $y_n$ etex, point .5 of ord[n]); 111 | 112 | endfig; 113 | end. 114 | } 115 | \medbreak 116 | \centerline{\epsfbox{numint-1.eps}} 117 | \medbreak 118 | 119 | According to Simpson’s rule, we divide 120 | the interval of integration $[a,b]$ 121 | into $n$ evenly spaced 122 | intervals, where $n$ is even. (The larger $n$ 123 | is, the better the approximation.) 124 | The interval boundaries constitute 125 | $n+1$ points on the $x$-axis, viz., $x_0$, $x_1$, 126 | \dots, $x_i$, $x_{i+1}$, \dots, $x_n$, where 127 | $x_0 = a$ and $x_n = b$. 128 | The length of each 129 | interval is $h = (b - a)/n$, so each $x_i = a+ih$. We then 130 | calculate the ordinates of $f(x)$ at the interval 131 | boundaries. There are $n+1$ such ordinates, viz., 132 | $y_0$, \dots, $y_i$, \dots, $y_n$, where $y_i = f(x_i) 133 | = f(a+ih)$. 134 | Simpson’s rule 135 | approximates the definite integral of $f(x)$ between 136 | $a$ and $b$ with the value\f{Consult any elementary 137 | text on the calculus for an explanation of why this 138 | approximation is reasonable.}: 139 | 140 | $$ 141 | {h\over 3} \left[ (y_0 + y_n) 142 | + 4(y_1 + y_3 + \cdots + y_{n-1}) 143 | + 2(y_2 + y_4 + \cdots + y_{n-2}) \right] 144 | $$ 145 | % 146 | We define 147 | the procedure \q{integrate-simpson} 148 | to take four arguments: the integrand \q{f}; the 149 | $x$-values at the limits \q{a} and \q{b}; and the 150 | number of intervals \q{n}. 151 | 152 | \scmfilename simpson.scm 153 | \scmdribble{ 154 | (define integrate-simpson 155 | (lambda (f a b n) 156 | ;... 157 | } 158 | 159 | \n The first thing we do in 160 | \q{integrate-simpson}’s body is ensure that 161 | \q{n} is even — if it isn’t, we simply bump its 162 | value by 1. 163 | 164 | \scmdribble{ 165 | ;... 166 | (unless (even? n) (set! n (+ n 1))) 167 | ;... 168 | } 169 | 170 | \n Next, we put in the local variable \q{h} 171 | the length of the interval. We introduce two more local variables 172 | \q{h*2} and \q{n/2} to store the values of twice \q{h} 173 | and half \q{n} respectively, as we expect to 174 | use these values often in the ensuing calculations. 175 | 176 | \scmdribble{ 177 | ;... 178 | (let* ((h (/ (- b a) n)) 179 | (h*2 (* h 2)) 180 | (n/2 (/ n 2)) 181 | ;... 182 | } 183 | 184 | \n We note that the sums $y_1 + y_3 + \cdots + y_{n-1}$ 185 | and $y_2 + y_4 + \cdots + y_{n-2}$ both involve adding 186 | every other ordinate. So let’s define a local procedure 187 | \q{sum-every-other-ordinate-starting-from} that 188 | captures this common iteration. By abstracting this 189 | iteration into a procedure, we avoid having to repeat 190 | the iteration textually. This not only reduces 191 | clutter, but reduces the chance of error, since we have 192 | only one textual occurrence of the iteration to debug. 193 | 194 | \q{sum-every-other-ordinate-starting-from} takes two arguments: 195 | the starting ordinate and the number of ordinates to be summed. 196 | 197 | \scmdribble{ 198 | ;... 199 | (sum-every-other-ordinate-starting-from 200 | (lambda (x0 num-ordinates) 201 | (let loop ((x x0) (i 0) (r 0)) 202 | (if (>= i num-ordinates) r 203 | (loop (+ x h*2) 204 | (+ i 1) 205 | (+ r (f x))))))) 206 | ;... 207 | } 208 | 209 | \n We can now calculate the three ordinate sums, and 210 | combine them to produce the final answer. Note 211 | that there are $n/2$ terms in $y_1 + y_3 + \cdots + 212 | y_{n-1}$, and $(n/2) - 1$ terms in $y_2 + y_4 + \cdots 213 | + y_{n-2}$. 214 | 215 | \scmdribble{ 216 | ;... 217 | (y0+yn (+ (f a) (f b))) 218 | (y1+y3+...+y.n-1 219 | (sum-every-other-ordinate-starting-from 220 | (+ a h) n/2)) 221 | (y2+y4+...+y.n-2 222 | (sum-every-other-ordinate-starting-from 223 | (+ a h*2) (- n/2 1)))) 224 | (* 1/3 h 225 | (+ y0+yn 226 | (* 4.0 y1+y3+...+y.n-1) 227 | (* 2.0 y2+y4+...+y.n-2)))))) 228 | } 229 | 230 | \n Let’s use \q{integrate-simpson} to find the definite 231 | integral of the function 232 | 233 | $$ 234 | \phi(x) = {1\over \sqrt{2\pi}} e^{-x^2/2} 235 | $$ 236 | % 237 | We first define $\phi$ in Scheme’s prefix 238 | notation.\f{$\phi$ 239 | is the probability density of a 240 | random variable with a {\em normal} or {\em Gaussian} 241 | distribution, with mean = 0 and standard deviation = 1. 242 | The definite integral $\int_0^z \phi(x) dx$ 243 | is the probability that the random 244 | variable assumes a value between 0 and $z$. 245 | However, you don’t need to know all this in 246 | order to understand the example!} 247 | 248 | \scmdribble{ 249 | (define *pi* (* 4 (atan 1))) 250 | 251 | (define phi 252 | (lambda (x) 253 | (* (/ 1 (sqrt (* 2 *pi*))) 254 | (exp (- (* 1/2 (* x x))))))) 255 | } 256 | 257 | \n Note that we exploit the fact that $\tan^{-1} 1 = 258 | \pi/4$ in order to define \q{*pi*}.\f{If Scheme didn’t 259 | have the \q{atan} procedure, we could use our 260 | numerical-integration procedure to get an approximation 261 | for $\int_0^1 (1 + x^2)^{-1} dx$, which is $\pi/4$.} 262 | 263 | The following calls calculate the definite integrals of 264 | \q{phi} from 0 to 1, 2, and 3 respectively. They 265 | all use 10 intervals. 266 | 267 | \q{ 268 | (integrate-simpson phi 0 1 10) 269 | (integrate-simpson phi 0 2 10) 270 | (integrate-simpson phi 0 3 10) 271 | } 272 | 273 | \n To four decimal places, these values should be 274 | 0.3413, 0.4772, and 0.4987 respectively \cite[Table 275 | 26.1]{hmf}. Check to see that our implementation 276 | of Simpson’s rule does indeed produce comparable 277 | values!\f{By pulling constant factors — such as \q{(/ 278 | 1 (sqrt (* 2 *pi*)))} in \q{phi} — out of the 279 | integrand, we could speed up the ordinate calculations 280 | within \q{integrate-simpson}.} 281 | 282 | \section{Adaptive interval sizes} 283 | 284 | It is not always convenient to specify the number \q{n} 285 | of intervals. A number that is good enough for 286 | one integrand may be woefully inadequate for another. In 287 | such cases, it is better to specify the amount of 288 | {\it tolerance\/} \q{e} we are willing to grant the final answer, and let 289 | the program figure out how many intervals are needed. A 290 | typical way to accomplish this is to have the program 291 | try increasingly better answers by steadily increasing 292 | \q{n}, and stop when two successive sums differ within 293 | \q{e}. Thus: 294 | 295 | \q{ 296 | (define integrate-adaptive-simpson-first-try 297 | (lambda (f a b e) 298 | (let loop ((n 4) 299 | (iprev (integrate-simpson f a b 2))) 300 | (let ((icurr (integrate-simpson f a b n))) 301 | (if (<= (abs (- icurr iprev)) e) 302 | icurr 303 | (loop (+ n 2))))))) 304 | } 305 | 306 | \n Here we calculate successive Simpson integrals (using 307 | our original procedure \q{integrate-simpson}) for 308 | \q{n} = 2, 4, \dots. (Remember that \q{n} must be even.) 309 | When the integral \q{icurr} for the current \q{n} 310 | differs within \q{e} from the integral \q{iprev} for 311 | the immediately preceding \q{n}, we return \q{icurr}. 312 | 313 | One problem with this approach is that we don’t take 314 | into account that only some {\it segments\/} of the 315 | function benefit from the addition of intervals. For 316 | the other segments, the addition of intervals merely 317 | increases the computation without contributing to a 318 | better overall answer. For an improved adaptation, we 319 | could split the integral into adjacent segments, and 320 | improve each segment separately. 321 | 322 | \q{ 323 | (define integrate-adaptive-simpson-second-try 324 | (lambda (f a b e) 325 | (let integrate-segment ((a a) (b b) (e e)) 326 | (let ((i2 (integrate-simpson f a b 2)) 327 | (i4 (integrate-simpson f a b 4))) 328 | (if (<= (abs (- i2 i4)) e) 329 | i4 330 | (let ((c (/ (+ a b) 2)) 331 | (e (/ e 2))) 332 | (+ (integrate-segment a c e) 333 | (integrate-segment c b e)))))))) 334 | } 335 | 336 | \n The initial segment is from \q{a} to \q{b}. To find 337 | the integral for a segment, we calculate the Simpson 338 | integrals \q{i2} and \q{i4} with the two smallest 339 | interval numbers 2 and 4. If these are within \q{e} of 340 | each other, we return \q{i4}. If not we split the 341 | segment in half, recursively calculate the integral 342 | separately for each segment, and add. In 343 | general, different segments at the same level converge 344 | at their own pace. Note that when we integrate a half 345 | of a segment, we take care to also halve the tolerance, 346 | so that the precision of the eventual sum does not 347 | decay. 348 | 349 | There are still some inefficiencies in this 350 | procedure: The integral \q{i4} recalculates three 351 | ordinates already determined by \q{i2}, and the integral 352 | of each half-segment recalculates three ordinates 353 | already determined by \q{i2} and \q{i4}. We avoid 354 | these inefficiencies by making explicit the sums used 355 | for \q{i2} and \q{i4}, and by transmitting more parameters 356 | in the named-\q{let} \q{integrate-segment}. This makes for 357 | more sharing, both within the body of \q{integrate-segment} 358 | and across successive calls to \q{integrate-segment}: 359 | 360 | \scmdribble{ 361 | (define integrate-adaptive-simpson 362 | (lambda (f a b e) 363 | (let* ((h (/ (- b a) 4)) 364 | (mid.a.b (+ a (* 2 h)))) 365 | (let integrate-segment ((x0 a) 366 | (x2 mid.a.b) 367 | (x4 b) 368 | (y0 (f a)) 369 | (y2 (f mid.a.b)) 370 | (y4 (f b)) 371 | (h h) 372 | (e e)) 373 | (let* ((x1 (+ x0 h)) 374 | (x3 (+ x2 h)) 375 | (y1 (f x1)) 376 | (y3 (f x3)) 377 | (i2 (* 2/3 h (+ y0 y4 (* 4.0 y2)))) 378 | (i4 (* 1/3 h (+ y0 y4 (* 4.0 (+ y1 y3)) 379 | (* 2.0 y2))))) 380 | (if (<= (abs (- i2 i4)) e) 381 | i4 382 | (let ((h (/ h 2)) (e (/ e 2))) 383 | (+ (integrate-segment 384 | x0 x1 x2 y0 y1 y2 h e) 385 | (integrate-segment 386 | x2 x3 x4 y2 y3 y4 h e))))))))) 387 | } 388 | 389 | \n \q{integrate-segment} now explicitly sets four 390 | intervals of size \q{h}, giving five ordinates \q{y0}, 391 | \q{y1}, \q{y2}, \q{y3}, and \q{y4}. The integral 392 | \q{i4} uses all of these ordinates, while the integral 393 | \q{i2} uses just \q{y0}, \q{y2}, and \q{y4}, with an 394 | interval size of twice \q{h}. It is easy to verify that 395 | the explicit sums used for \q{i2} and \q{i4} do correspond 396 | to Simpson sums. 397 | 398 | Compare the following approximations of 399 | $\int_0^{20} e^x dx$: 400 | 401 | \q{ 402 | (integrate-simpson exp 0 20 10) 403 | (integrate-simpson exp 0 20 20) 404 | (integrate-simpson exp 0 20 40) 405 | (integrate-adaptive-simpson exp 0 20 .001) 406 | (- (exp 20) 1) 407 | } 408 | 409 | \n The last one is the analytically correct answer. See 410 | if you can figure out the smallest \q{n} (overshooting is 411 | expensive!) 412 | such that \q{(integrate-simpson exp 0 20 n)} yields a result 413 | comparable to that returned by the \q{integrate-adaptive-simpson} 414 | call. 415 | 416 | \input gamma 417 | -------------------------------------------------------------------------------- /callcc.tex: -------------------------------------------------------------------------------- 1 | \chapter{Jumps} 2 | 3 | \index{call-with-current-continuation@\q{call-with-current-continuation}|see{\q{call/cc}}} 4 | One of the signal features of Scheme is its support for 5 | jumps or {\em nonlocal control}. Specifically, Scheme 6 | allows program control to jump to {\em arbitrary} 7 | locations in the program, in contrast to the more 8 | restrained forms of program control flow allowed by 9 | conditionals and procedure calls. Scheme’s nonlocal 10 | control operator is a procedure named 11 | \q{call-with-current-continuation}. We will 12 | see how this operator can be used to create a 13 | breathtaking variety of control idioms. 14 | 15 | \section{\q{call-with-current-continuation}} 16 | 17 | \index{call/cc@\q{call/cc}} 18 | \index{continuation} 19 | The operator \q{call-with-current-continuation} {\em 20 | call}s its argument, which must be a unary procedure, 21 | {\em with} a value called the “{\em current 22 | continuation}”. If nothing else, this explains the 23 | name of the operator. But it is a long name, and is 24 | often abbreviated 25 | \q{call/cc}.\f{If your Scheme does not already have this 26 | abbreviation, include 27 | \q{(define call/cc call-with-current-continuation)} in 28 | your initialization code and protect yourself from 29 | RSI.} 30 | 31 | The current continuation at any point in the execution 32 | of a program is an abstraction of the {\em rest of the 33 | program}. Thus in the program 34 | 35 | \q{ 36 | (+ 1 (call/cc 37 | (lambda (k) 38 | (+ 2 (k 3))))) 39 | } 40 | 41 | \n 42 | the rest of the program, from the point of view of the 43 | \q{call/cc}-application, is the following 44 | program-with-a-hole (with \q{[]} representing the 45 | hole): 46 | 47 | \q{ 48 | (+ 1 []) 49 | } 50 | 51 | \n 52 | In other words, this continuation is a program that 53 | will add \q{1} to whatever is used to fill its hole. 54 | 55 | This is what the argument of \q{call/cc} is {\em called 56 | with}. Remember that the argument of \q{call/cc} is 57 | the procedure 58 | 59 | \q{ 60 | (lambda (k) 61 | (+ 2 (k 3))) 62 | } 63 | 64 | \n 65 | This procedure’s body applies the continuation (bound 66 | now to the parameter \q{k}) to the argument \q{3}. 67 | This is when the unusual aspect of the continuation 68 | springs to the fore. The continuation call abruptly 69 | abandons its own computation and replaces it with the 70 | rest of the program saved in \q{k}! In other words, 71 | the part of the procedure involving the addition of 72 | \q{2} is jettisoned, and \q{k}’s argument \q{3} is sent 73 | directly to the program-with-the-hole: 74 | 75 | \q{ 76 | (+ 1 []) 77 | } 78 | 79 | \n 80 | The program now running is simply 81 | 82 | \q{ 83 | (+ 1 3) 84 | } 85 | 86 | \n 87 | which returns \q{4}. In sum, 88 | 89 | \q{ 90 | (+ 1 (call/cc 91 | (lambda (k) 92 | (+ 2 (k 3))))) 93 | |evalsto 4 94 | } 95 | 96 | \n 97 | The above illustrates what is called an {\em 98 | escaping} continuation, one used to exit out of a 99 | computation (here: the \q{(+ 2 [])} computation). This 100 | is a useful property, but Scheme’s continuations can 101 | also be used to return to previously abandoned 102 | contexts, and indeed to invoke them many times. The 103 | “rest of the program” enshrined in a continuation is 104 | available whenever and how many ever times we choose to 105 | recall it, and this is what contributes to the great 106 | and sometimes confusing versatility of \q{call/cc}. As 107 | a quick example, type the following at the listener: 108 | 109 | \q{ 110 | (define r #f) 111 | 112 | (+ 1 (call/cc 113 | (lambda (k) 114 | (set! r k) 115 | (+ 2 (k 3))))) 116 | |evalsto 4 117 | } 118 | 119 | \n 120 | The latter expression returns \q{4} as before. The 121 | difference between this use of \q{call/cc} and the 122 | previous example is that here we also store the 123 | continuation \q{k} in a global variable \q{r}. 124 | 125 | Now we have a permanent record of the continuation in 126 | \q{r}. If we call it on a number, it will return that 127 | number incremented by \q{1}: 128 | 129 | \q{ 130 | (r 5) 131 | |evalsto 6 132 | } 133 | 134 | \n 135 | Note that \q{r} will abandon its own continuation, 136 | which is better illustrated by embedding the call to 137 | \q{r} inside some context: 138 | 139 | \q{ 140 | (+ 3 (r 5)) 141 | |evalsto 6 142 | } 143 | 144 | \n 145 | The continuations provided by \q{call/cc} are thus 146 | {\em abortive} continuations. 147 | 148 | \section{Escaping continuations} 149 | 150 | Escaping continuations are the simplest use of 151 | \q{call/cc} and are very useful for programming 152 | procedure or loop exits. Consider a procedure 153 | \q{list-product} that takes a list of numbers and 154 | multiplies them. A straightforward recursive 155 | definition for \q{list-product} is: 156 | 157 | \scmfilename listprod-fun.scm 158 | 159 | \scmdribble{ 160 | (define list-product 161 | (lambda (s) 162 | (let recur ((s s)) 163 | (if (null? s) 1 164 | (* (car s) (recur (cdr s))))))) 165 | } 166 | 167 | \n 168 | There is a problem with this solution. If one of the 169 | elements in the list is \q{0}, and if there are many 170 | elements after \q{0} in the list, then the answer is a 171 | foregone conclusion. Yet, the code will have us go 172 | through many fruitless recursive calls to \q{recur} 173 | before producing the answer. This is where an escape 174 | continuation comes in handy. Using \q{call/cc}, we can 175 | rewrite the procedure as: 176 | 177 | \scmfilename listprod-cwcc.scm 178 | 179 | \scmdribble{ 180 | (define list-product 181 | (lambda (s) 182 | (call/cc 183 | (lambda (exit) 184 | (let recur ((s s)) 185 | (if (null? s) 1 186 | (if (= (car s) 0) (exit 0) 187 | (* (car s) (recur (cdr s)))))))))) 188 | } 189 | 190 | \n 191 | If a \q{0} element is encountered, the continuation 192 | \q{exit} is called with \q{0}, thereby avoiding 193 | further calls to \q{recur}. 194 | 195 | \section{Tree matching} 196 | 197 | A more involved example of continuation usage is the 198 | problem of determining if two trees (arbitrarily nested 199 | dotted pairs) have the same {\em fringe}, i.e., the 200 | same elements (or {\em leaves}) in the same sequence. 201 | E.g., 202 | 203 | \q{ 204 | (same-fringe? '(1 (2 3)) '((1 2) 3)) 205 | |evalsto #t 206 | 207 | (same-fringe? '(1 2 3) '(1 (3 2))) 208 | |evalsto #f 209 | } 210 | 211 | The purely functional approach is to flatten both trees 212 | and check if the results match. 213 | 214 | \scmfilename fringe-fun.scm 215 | 216 | \scmdribble{ 217 | (define same-fringe? 218 | (lambda (tree1 tree2) 219 | (let loop ((ftree1 (flatten tree1)) 220 | (ftree2 (flatten tree2))) 221 | (cond ((and (null? ftree1) (null? ftree2)) #t) 222 | ((or (null? ftree1) (null? ftree2)) #f) 223 | ((eqv? (car ftree1) (car ftree2)) 224 | (loop (cdr ftree1) (cdr ftree2))) 225 | (else #f))))) 226 | 227 | (define flatten 228 | (lambda (tree) 229 | (cond ((null? tree) '()) 230 | ((pair? (car tree)) 231 | (append (flatten (car tree)) 232 | (flatten (cdr tree)))) 233 | (else 234 | (cons (car tree) 235 | (flatten (cdr tree))))))) 236 | } 237 | 238 | \n 239 | However, this traverses the trees completely to flatten 240 | them, and then again till it finds non-matching 241 | elements. Furthermore, even the best flattening 242 | algorithms will require \q{cons}es equal to the total 243 | number of leaves. (Destructively modifying the input 244 | trees is not an option.) 245 | 246 | We can use \q{call/cc} to solve the problem without 247 | needless traversal and without any \q{cons}ing. Each 248 | tree is mapped to a {\em generator}, a procedure with 249 | internal state that successively produces the leaves of 250 | the tree in the left-to-right order that they occur in 251 | the tree. 252 | 253 | \scmfilename fringe-cwcc.scm 254 | 255 | \scmdribble{ 256 | (define tree->generator 257 | (lambda (tree) 258 | (let ((caller '*)) 259 | (letrec 260 | ((generate-leaves 261 | (lambda () 262 | (let loop ((tree tree)) 263 | (cond ((null? tree) 'skip) 264 | ((pair? tree) 265 | (loop (car tree)) 266 | (loop (cdr tree))) 267 | (else 268 | (call/cc 269 | (lambda (rest-of-tree) 270 | (set! generate-leaves 271 | (lambda () 272 | (rest-of-tree 'resume))) 273 | (caller tree)))))) 274 | (caller '())))) 275 | (lambda () 276 | (call/cc 277 | (lambda (k) 278 | (set! caller k) 279 | (generate-leaves)))))))) 280 | } 281 | 282 | \n 283 | When a generator created by \q{tree->generator} is 284 | called, it will store the continuation of its call in 285 | \q{caller}, so that it can know who to send the leaf to 286 | when it finds it. It then calls an internal procedure 287 | called \q{generate-leaves} which runs a loop traversing 288 | the tree from left to right. When the loop encounters 289 | a leaf, it will use \q{caller} to return the leaf as 290 | the generator’s result, but it will remember to store 291 | the rest of the loop (captured as a \q{call/cc} 292 | continuation) in the \q{generate-leaves} variable. The 293 | next time the generator is called, the loop is resumed 294 | where it left off so it can hunt for the next leaf. 295 | 296 | Note that the last thing \q{generate-leaves} does, 297 | after the loop is done, is to return the empty list to 298 | the 299 | \q{caller}. Since the empty list is not a valid leaf 300 | value, we can use it to tell that the generator has 301 | no more leaves to generate. 302 | 303 | The procedure \q{same-fringe?} maps each of its tree 304 | arguments to a generator, and then calls these two 305 | generators alternately. It announces failure as soon 306 | as two non-matching leaves are found: 307 | 308 | \scmdribble{ 309 | (define same-fringe? 310 | (lambda (tree1 tree2) 311 | (let ((gen1 (tree->generator tree1)) 312 | (gen2 (tree->generator tree2))) 313 | (let loop () 314 | (let ((leaf1 (gen1)) 315 | (leaf2 (gen2))) 316 | (if (eqv? leaf1 leaf2) 317 | (if (null? leaf1) #t (loop)) 318 | #f)))))) 319 | } 320 | 321 | \n 322 | It is easy to see that the trees are traversed at most 323 | once, and in case of mismatch, the traversals extend 324 | only upto the leftmost mismatch. \q{cons} is not used. 325 | 326 | \index{coroutine} 327 | \index{call/cc@\q{call/cc}!and coroutine} 328 | 329 | \section{Coroutines} 330 | 331 | The generators used above are interesting 332 | generalizations of the procedure concept. Each time 333 | the generator is called, it resumes its computation, 334 | and when it has a result for its caller returns it, but 335 | only after storing its continuation in an internal 336 | variable so the generator can be resumed again. We can 337 | generalize generators further, so that they can 338 | mutually resume each other, sending results back and 339 | forth amongst themselves. Such procedures are called 340 | {\em coroutines}~\cite{coroutine}. 341 | 342 | We will view a coroutine as a unary procedure, whose 343 | body can contain \q{resume} calls. \q{resume} is a 344 | two-argument procedure used by a coroutine to resume 345 | another coroutine with a transfer value. The macro \q{coroutine} 346 | defines such a coroutine procedure, given a variable name for 347 | the coroutine’s initial argument, and the body of the coroutine. 348 | 349 | \scmfilename coroutine.scm 350 | 351 | \scmdribble{ 352 | (define-macro coroutine 353 | (lambda (x . body) 354 | `(letrec ((+local-control-state 355 | (lambda (,x) ,@body)) 356 | (resume 357 | (lambda (c v) 358 | (call/cc 359 | (lambda (k) 360 | (set! +local-control-state k) 361 | (c v)))))) 362 | (lambda (v) 363 | (+local-control-state v))))) 364 | } 365 | 366 | \n A call of this macro creates a coroutine procedure 367 | (let’s call it $A$) that can be called with one 368 | argument. $A$ has an internal variable called 369 | \q{+local-control-state} that stores, at any point, the 370 | remaining computation of the coroutine. Initially 371 | this is the entire coroutine computation. When 372 | \q{resume} is called — i.e., invoking another coroutine 373 | $B$ — the current coroutine will update its 374 | \q{+local-control-state} value to the rest of itself, 375 | stop itself, and then jump to the \q{resume}d coroutine 376 | $B$. When coroutine $A$ is itself \q{resume}d at 377 | some later point, its computation will proceed from the 378 | continuation stored in its \q{+local-control-state}. 379 | 380 | \scmfilename fringe-cor.scm 381 | 382 | \subsection{Tree-matching with coroutines} 383 | 384 | Tree-matching is further simplified using coroutines. 385 | The matching process is coded as a coroutine that 386 | depends on two other coroutines to supply the leaves of 387 | the respective trees: 388 | 389 | \scmdribble{ 390 | (define make-matcher-cor 391 | (lambda (tree-cor-1 tree-cor-2) 392 | (coroutine dummy-init-arg 393 | (let loop () 394 | (let ((leaf1 (resume tree-cor-1 'get-a-leaf)) 395 | (leaf2 (resume tree-cor-2 'get-a-leaf))) 396 | (if (eqv? leaf1 leaf2) 397 | (if (null? leaf1) #t (loop)) 398 | #f)))))) 399 | } 400 | 401 | \n 402 | The leaf-generator coroutines remember who to send 403 | their leaves to: 404 | 405 | \scmdribble{ 406 | (define make-leaf-gen-cor 407 | (lambda (tree matcher-cor) 408 | (coroutine dummy-init-arg 409 | (let loop ((tree tree)) 410 | (cond ((null? tree) 'skip) 411 | ((pair? tree) 412 | (loop (car tree)) 413 | (loop (cdr tree))) 414 | (else 415 | (resume matcher-cor tree)))) 416 | (resume matcher-cor '())))) 417 | } 418 | 419 | \n 420 | The \q{same-fringe?} procedure can now {\em almost} 421 | be written as 422 | 423 | \q{ 424 | (define same-fringe? 425 | (lambda (tree1 tree2) 426 | (letrec ((tree-cor-1 427 | (make-leaf-gen-cor 428 | tree1 429 | matcher-cor)) 430 | (tree-cor-2 431 | (make-leaf-gen-cor 432 | tree2 433 | matcher-cor)) 434 | (matcher-cor 435 | (make-matcher-cor 436 | tree-cor-1 437 | tree-cor-2))) 438 | (matcher-cor 'start-the-ball-rolling)))) 439 | } 440 | 441 | \n 442 | Unfortunately, Scheme’s \q{letrec} can resolve 443 | mutually recursive references amongst the lexical 444 | variables it introduces {\em only} if such variable 445 | references are wrapped inside a \q{lambda}. And so we 446 | write: 447 | 448 | \scmdribble{ 449 | (define same-fringe? 450 | (lambda (tree1 tree2) 451 | (letrec ((tree-cor-1 452 | (make-leaf-gen-cor 453 | tree1 454 | (lambda (v) (matcher-cor v)))) 455 | (tree-cor-2 456 | (make-leaf-gen-cor 457 | tree2 458 | (lambda (v) (matcher-cor v)))) 459 | (matcher-cor 460 | (make-matcher-cor 461 | (lambda (v) (tree-cor-1 v)) 462 | (lambda (v) (tree-cor-2 v))))) 463 | (matcher-cor 'start-the-ball-rolling)))) 464 | } 465 | 466 | \n 467 | Note that \q{call/cc} is not called directly at all in 468 | this rewrite of \q{same-fringe?}. All the continuation 469 | manipulation is handled for us by the 470 | \q{coroutine} macro. 471 | 472 | \input umbrella 473 | -------------------------------------------------------------------------------- /amb.tex: -------------------------------------------------------------------------------- 1 | \chapter{Nondeterminism} 2 | 3 | \index{nondeterminism} 4 | \index{logic programming} 5 | \index{amb@\q{amb}} 6 | McCarthy’s nondeterministic operator 7 | \q{amb} \cite{jmc:amb,wc:amb,zmc:amb} is as old as 8 | Lisp itself, although it is present in no Lisp. 9 | \q{amb} takes zero or more expressions, and makes a 10 | nondeterministic (or “ambiguous”) choice among them, 11 | preferring those choices that cause the program to 12 | converge meaningfully. Here we will explore an 13 | embedding of \q{amb} in Scheme that makes a depth-first 14 | selection of the ambiguous choices, and uses Scheme’s 15 | control operator \q{call/cc} to backtrack for alternate 16 | choices. The result is an elegant backtracking 17 | strategy that can be used for searching problem spaces 18 | directly in Scheme without recourse to an extended 19 | language. The embedding recalls the continuation 20 | strategies used to implement Prolog-style logic 21 | programming \cite{logick,mf:prolog}, but is sparer because the 22 | operator provided is much like a Scheme boolean 23 | operator, does not require special contexts for its 24 | use, and does not rely on linguistic infrastructure 25 | such as logic variables and unification. 26 | 27 | \section{Description of \q{amb}} 28 | 29 | An accessible description of \q{amb} and many example 30 | uses are found in the premier Scheme textbook 31 | SICP \cite{sicp}. Informally, 32 | \q{amb} takes zero or more expressions and {\em 33 | nondeterministically} returns the value of {\em one} of 34 | them. Thus, 35 | 36 | \q{ 37 | (amb 1 2) 38 | } 39 | 40 | \n may evaluate to 1 {\em or} 2. 41 | 42 | \q{amb} called with {\em no} expressions has no 43 | value to return, and is considered to {\em fail}. 44 | Thus, 45 | 46 | \q{ 47 | (amb) 48 | |causeserror amb tree exhausted 49 | } 50 | 51 | \n (We will examine the wording of the error message later.) 52 | 53 | In particular, \q{amb} is required to return a value if at 54 | least one its subexpressions converges, i.e., doesn’t fail. 55 | Thus, 56 | 57 | \q{ 58 | (amb 1 (amb)) 59 | } 60 | 61 | \n and 62 | 63 | \q{ 64 | (amb (amb) 1) 65 | } 66 | 67 | \n both return 1. 68 | 69 | Clearly, \q{amb} cannot simply be equated to its first 70 | subexpression, since it has to return a {\em non-failing} 71 | value, if this is at all possible. However, this is not 72 | all: The bias for convergence is more stringent than a 73 | merely local choice of \q{amb}’s subexpressions. \q{amb} 74 | should furthermore return {\em that} convergent value 75 | that makes the {\em entire program} converge. In 76 | denotational parlance, \q{amb} is an {\em angelic} 77 | operator. 78 | 79 | For example, 80 | 81 | \q{ 82 | (amb #f #t) 83 | } 84 | 85 | \n may return either \q{#f} or \q{#t}, but in the program 86 | 87 | \q{ 88 | (if (amb #f #t) 89 | 1 90 | (amb)) 91 | } 92 | 93 | \n the first \q{amb}-expression {\em must} return \q{#t}. 94 | If it returned \q{#f}, the \q{if}’s “else” branch would be 95 | chosen, which causes the entire program to fail. 96 | 97 | \section{Implementing \q{amb} in Scheme} 98 | 99 | In our implementation of \q{amb}, we will favor 100 | \q{amb}’s subexpressions from left to right. I.e., the 101 | first subexpression is chosen, and if it leads to overall 102 | failure, the second is picked, and so on. \q{amb}s occurring 103 | later in the control flow of the program are searched for 104 | alternates before backtracking to previous \q{amb}s. In 105 | other words, we perform a {\em depth-first} search of the 106 | \q{amb} {\em choice tree}, and whenever we brush against 107 | failure, we backtrack to the most recent node of the tree 108 | that offers a further choice. (This is called {\em 109 | chronological backtracking.}) 110 | 111 | We first define a mechanism for setting the base failure 112 | continuation: 113 | 114 | \scmfilename amb.scm 115 | \scmdribble{ 116 | (define amb-fail '*) 117 | 118 | (define initialize-amb-fail 119 | (lambda () 120 | (set! amb-fail 121 | (lambda () 122 | (error "amb tree exhausted"))))) 123 | 124 | (initialize-amb-fail) 125 | } 126 | 127 | \n When \q{amb} fails, it invokes the continuation bound at 128 | the time to \q{amb-fail}. This is the continuation invoked 129 | when all the alternates in the \q{amb} choice tree have been 130 | tried and were found to fail. 131 | 132 | We define \q{amb} as a macro that accepts an indefinite 133 | number of subexpressions. 134 | 135 | \scmdribble{ 136 | (define-macro amb 137 | (lambda alts... 138 | `(let ((+prev-amb-fail amb-fail)) 139 | (call/cc 140 | (lambda (+sk) 141 | 142 | ,@(map (lambda (alt) 143 | `(call/cc 144 | (lambda (+fk) 145 | (set! amb-fail 146 | (lambda () 147 | (set! amb-fail +prev-amb-fail) 148 | (+fk 'fail))) 149 | (+sk ,alt)))) 150 | alts...) 151 | 152 | (+prev-amb-fail)))))) 153 | } 154 | 155 | \n A call to \q{amb} first stores away, in 156 | \q{+prev-amb-fail}, the \q{amb-fail} value that was 157 | current at the time of entry. This is because the 158 | \q{amb-fail} variable will be set to different failure 159 | continuations as the various alternates are tried. 160 | 161 | We then capture the \q{amb}’s {\em entry} continuation \q{+sk}, so 162 | that when one of the alternates evaluates to a non-failing 163 | value, it can immediately exit the \q{amb}. 164 | 165 | Each alternate \q{alt} is tried in sequence (the 166 | implicit-\q{begin} sequence of Scheme). 167 | 168 | First, we capture the current continuation \q{+fk}, wrap it 169 | in a procedure and set \q{amb-fail} to that procedure. The 170 | alternate is then evaluated as \q{(+sk alt)}. If \q{alt} 171 | evaluates without failure, its return value is fed to the 172 | continuation \q{+sk}, which immediately exits the \q{amb} 173 | call. If \q{alt} fails, it calls \q{amb-fail}. The first 174 | duty of \q{amb-fail} is to reset \q{amb-fail} to the value 175 | it had at the time of entry. It then invokes the failure 176 | continuation \q{+fk}, which causes the next alternate, if 177 | any, to be tried. 178 | 179 | If all alternates fail, the \q{amb-fail} at \q{amb} entry, 180 | which we had stored in \q{+prev-amb-fail}, is 181 | called. 182 | 183 | \section{Using \q{amb} in Scheme} 184 | 185 | To choose a number between 1 and 10, one could say 186 | 187 | \q{ 188 | (amb 1 2 3 4 5 6 7 8 9 10) 189 | } 190 | 191 | \n To be sure, as a program, this will give 1, but 192 | depending on the context, it could return any of the 193 | mentioned numbers. 194 | 195 | The procedure \q{number-between} is 196 | a more abstract way to generate numbers from a given \q{lo} 197 | to a given \q{hi} (inclusive): 198 | 199 | \q{ 200 | (define number-between 201 | (lambda (lo hi) 202 | (let loop ((i lo)) 203 | (if (> i hi) (amb) 204 | (amb i (loop (+ i 1))))))) 205 | } 206 | 207 | \n Thus \q{(number-between 1 6)} will first 208 | generate 1. Should that fail, the \q{loop} iterates, 209 | producing 2. Should {\em that} fail, we get 3, and 210 | so on, until 6. After 6, \q{loop} is called with 211 | the number 7, which being more than 6, invokes 212 | \q{(amb)}, which causes final failure. (Recall that 213 | \q{(amb)} by itself guarantees 214 | failure.) At this point, the program containing the 215 | call to 216 | \q{(number-between 1 6)} will backtrack to the 217 | chronologically previous \q{amb}-call, and try to 218 | satisfy {\em that} call in another fashion. 219 | 220 | The guaranteed failure of \q{(amb)} can be used to program 221 | {\em assertions}. 222 | 223 | \q{ 224 | (define assert 225 | (lambda (pred) 226 | (if (not pred) (amb)))) 227 | } 228 | 229 | \n The call \q{(assert pred)} insists that \q{pred} be 230 | true. Otherwise it will cause the current \q{amb} choice 231 | point to fail.\f{SICP names this procedure 232 | \q{require}. We use the identifier \q{assert} in order to 233 | avoid confusion with the popular if informal use of 234 | the identifier \q{require} for something else, viz.., an 235 | operator that loads code modules on a per-need basis.} 236 | 237 | Here is a procedure using \q{assert} that generates a prime 238 | less than or equal to its argument \q{hi}: 239 | 240 | \q{ 241 | (define gen-prime 242 | (lambda (hi) 243 | (let ((i (number-between 2 hi))) 244 | (assert (prime? i)) 245 | i))) 246 | } 247 | 248 | \n This seems devilishly simple, except that when called as 249 | a program with any number (say 20), it will produce the 250 | uninteresting first solution, i.e., 2. 251 | 252 | We would certainly like to get {\em all} the solutions, 253 | not just the first. In this case, we may want {\em all} 254 | the primes below 255 | 20. One way is to explicitly call the failure 256 | continuation left after the program has produced its first 257 | solution. Thus, 258 | 259 | \q{ 260 | (amb) 261 | => 3 262 | } 263 | 264 | \n This leaves yet another failure continuation, which can 265 | be called again for yet another solution: 266 | 267 | \q{ 268 | (amb) 269 | => 5 270 | } 271 | 272 | \n The problem with this method is that the program is 273 | initially called at the Scheme prompt, and successive 274 | solutions are also obtained by calling \q{amb} at the Scheme 275 | prompt. In effect, we are using different programs (we 276 | cannot predict how many!), carrying over information from a 277 | previous program to the next. Instead, we would like to be 278 | able to get these solutions as the return value of a 279 | form that we can call in any context. To this end, we 280 | define the 281 | \q{bag-of} macro, which returns all 282 | the successful instantiations of its argument. (If the argument 283 | never succeeds, \q{bag-of} returns the empty list.) 284 | Thus, we could say, 285 | 286 | \q{ 287 | (bag-of 288 | (gen-prime 20)) 289 | } 290 | 291 | \n and it would return 292 | 293 | \q{ 294 | (2 3 5 7 11 13 17 19) 295 | } 296 | 297 | \n The \q{bag-of} macro is defined as follows: 298 | 299 | \q{ 300 | (define-macro bag-of 301 | (lambda (e) 302 | `(let ((+prev-amb-fail amb-fail) 303 | (+results '())) 304 | (if (call/cc 305 | (lambda (+k) 306 | (set! amb-fail (lambda () (+k #f))) 307 | (let ((+v ,e)) 308 | (set! +results (cons +v +results)) 309 | (+k #t)))) 310 | (amb-fail)) 311 | (set! amb-fail +prev-amb-fail) 312 | (reverse! +results)))) 313 | } 314 | 315 | \n \q{bag-of} first saves away its entry \q{amb-fail}. It 316 | redefines \q{amb-fail} to a local continuation \q{+k} created within an 317 | \q{if}-test. Inside the test, the \q{bag-of} argument \q{e} 318 | is evaluated. 319 | If \q{e} succeeds, its result is collected 320 | into a list called \q{+results}, and the local continuation 321 | is called with the value \q{#t}. This causes the 322 | \q{if}-test to succeed, causing \q{e} to be {\em retried} at its 323 | next backtrack point. More results for \q{e} are obtained this 324 | way, and they are all collected into \q{+results}. 325 | 326 | Finally, when \q{e} fails, it will call the base 327 | \q{amb-fail}, which is simply a call to the local 328 | continuation with the value \q{#f}. This pushes control 329 | past the \q{if}. We restore \q{amb-fail} to 330 | its pre-entry value, and return the \q{+results}. (The 331 | \q{reverse!} is simply to produce the results in the order 332 | in which they were generated.) 333 | 334 | \index{puzzles} 335 | \section{Logic puzzles} 336 | 337 | The power of depth-first search coupled 338 | with backtracking becomes obvious when applied to solving 339 | logic puzzles. These problems are extraordinarily difficult 340 | to solve procedurally, but can be solved concisely and 341 | declaratively with \q{amb}, without taking anything away 342 | from the charm of solving the puzzle. 343 | 344 | \subsection{The Kalotan puzzle} 345 | 346 | The Kalotans are a tribe with a peculiar quirk.\f{This 347 | puzzle is due to Hunter \cite{hunter}.} Their males always 348 | tell the truth. Their females never make two consecutive 349 | true statements, or two consecutive untrue statements. 350 | 351 | An anthropologist (let’s call him Worf) has begun to 352 | study them. Worf does not yet know the Kalotan 353 | language. One day, he meets a Kalotan (heterosexual) 354 | couple and their child Kibi. Worf asks Kibi: “Are you 355 | a boy?” Kibi answers in Kalotan, which of course Worf 356 | doesn’t understand. 357 | 358 | Worf turns to the parents (who know English) for 359 | explanation. One of them says: “Kibi said: ‘I am a 360 | boy.’ ” The other adds: “Kibi is a girl. Kibi lied.” 361 | 362 | Solve for the sex of the parents and Kibi. 363 | 364 | \centerline{—} 365 | 366 | The solution consists in introducing a bunch of variables, 367 | allowing them to take a choice of values, and 368 | enumerating the conditions on them as a sequence of 369 | \q{assert} expressions. 370 | 371 | The variables: \q{parent1}, 372 | \q{parent2}, and \q{kibi} are the sexes of the parents (in 373 | order of appearance) and Kibi; \q{kibi-self-desc} is 374 | the sex Kibi claimed to be (in Kalotan); \q{kibi-lied?} 375 | is the boolean on whether Kibi’s claim was a lie. 376 | 377 | \q{ 378 | (define solve-kalotan-puzzle 379 | (lambda () 380 | (let ((parent1 (amb 'm 'f)) 381 | (parent2 (amb 'm 'f)) 382 | (kibi (amb 'm 'f)) 383 | (kibi-self-desc (amb 'm 'f)) 384 | (kibi-lied? (amb #t #f))) 385 | (assert 386 | (distinct? (list parent1 parent2))) 387 | (assert 388 | (if (eqv? kibi 'm) 389 | (not kibi-lied?))) 390 | (assert 391 | (if kibi-lied? 392 | (xor 393 | (and (eqv? kibi-self-desc 'm) 394 | (eqv? kibi 'f)) 395 | (and (eqv? kibi-self-desc 'f) 396 | (eqv? kibi 'm))))) 397 | (assert 398 | (if (not kibi-lied?) 399 | (xor 400 | (and (eqv? kibi-self-desc 'm) 401 | (eqv? kibi 'm)) 402 | (and (eqv? kibi-self-desc 'f) 403 | (eqv? kibi 'f))))) 404 | (assert 405 | (if (eqv? parent1 'm) 406 | (and 407 | (eqv? kibi-self-desc 'm) 408 | (xor 409 | (and (eqv? kibi 'f) 410 | (eqv? kibi-lied? #f)) 411 | (and (eqv? kibi 'm) 412 | (eqv? kibi-lied? #t)))))) 413 | (assert 414 | (if (eqv? parent1 'f) 415 | (and 416 | (eqv? kibi 'f) 417 | (eqv? kibi-lied? #t)))) 418 | (list parent1 parent2 kibi)))) 419 | } 420 | 421 | \n A note on the helper procedures: The procedure 422 | \q{distinct?} returns true if all the elements in its 423 | argument list are distinct, and false otherwise. The 424 | procedure \q{xor} returns true if only one of its two 425 | arguments is true, and false otherwise. 426 | 427 | Typing \q{(solve-kalotan-puzzle)} will solve the puzzle. 428 | 429 | \subsection{Map coloring} 430 | 431 | It has been known for some time (but not proven until 432 | 1976~\cite{4cp}) that four colors suffice to 433 | color a terrestrial map — i.e., to color the countries 434 | so that neighbors are distinguished. To actually 435 | assign the colors is still an undertaking, and the 436 | following program shows how nondeterministic 437 | programming can help. 438 | 439 | The following program solves the problem of coloring a 440 | map of Western Europe. The problem and a Prolog 441 | solution are given in {\em The Art of 442 | Prolog} \cite{aop}. (It is instructive to compare 443 | our solution with the book’s.) 444 | 445 | %\input weurope 446 | 447 | The procedure \q{choose-color} nondeterministically 448 | returns one of four colors: 449 | 450 | \q{ 451 | (define choose-color 452 | (lambda () 453 | (amb 'red 'yellow 'blue 'white))) 454 | } 455 | 456 | \n In our solution, we create for each country a data 457 | structure. The data structure is a 3-element list: The 458 | first element of the list is the country’s name; the 459 | second element is its assigned color; and the third 460 | element is the colors of its neighbors. Note we use 461 | the initial of the country for its color 462 | variable.\f{Spain (Espa\~na) has \q{e} so as not to 463 | clash with Switzerland.} E.g., the list for Belgium is 464 | \q{(list 'belgium b (list f h l g))}, because — per 465 | the problem statement — the neighbors of Belgium are 466 | France, Holland, Luxembourg, and Germany. 467 | 468 | Once we create the lists for each country, we state the 469 | (single!) condition they should satisfy, viz., no 470 | country should have the color of its neighbors. In 471 | other words, for every country list, the second element 472 | should not be a member of the third element. 473 | 474 | \q{ 475 | (define color-europe 476 | (lambda () 477 | 478 | ;choose colors for each country 479 | (let ((p (choose-color)) ;Portugal 480 | (e (choose-color)) ;Spain 481 | (f (choose-color)) ;France 482 | (b (choose-color)) ;Belgium 483 | (h (choose-color)) ;Holland 484 | (g (choose-color)) ;Germany 485 | (l (choose-color)) ;Luxemb 486 | (i (choose-color)) ;Italy 487 | (s (choose-color)) ;Switz 488 | (a (choose-color)) ;Austria 489 | ) 490 | 491 | ;construct the adjacency list for 492 | ;each country: the 1st element is 493 | ;the name of the country; the 2nd 494 | ;element is its color; the 3rd 495 | ;element is the list of its 496 | ;neighbors’ colors 497 | (let ((portugal 498 | (list 'portugal p 499 | (list e))) 500 | (spain 501 | (list 'spain e 502 | (list f p))) 503 | (france 504 | (list 'france f 505 | (list e i s b g l))) 506 | (belgium 507 | (list 'belgium b 508 | (list f h l g))) 509 | (holland 510 | (list 'holland h 511 | (list b g))) 512 | (germany 513 | (list 'germany g 514 | (list f a s h b l))) 515 | (luxembourg 516 | (list 'luxembourg l 517 | (list f b g))) 518 | (italy 519 | (list 'italy i 520 | (list f a s))) 521 | (switzerland 522 | (list 'switzerland s 523 | (list f i a g))) 524 | (austria 525 | (list 'austria a 526 | (list i s g)))) 527 | (let ((countries 528 | (list portugal spain 529 | france belgium 530 | holland germany 531 | luxembourg 532 | italy switzerland 533 | austria))) 534 | 535 | ;the color of a country 536 | ;should not be the color of 537 | ;any of its neighbors 538 | (for-each 539 | (lambda (c) 540 | (assert 541 | (not (memq (cadr c) 542 | (caddr c))))) 543 | countries) 544 | 545 | ;output the color 546 | ;assignment 547 | (for-each 548 | (lambda (c) 549 | (display (car c)) 550 | (display " ") 551 | (display (cadr c)) 552 | (newline)) 553 | countries)))))) 554 | } 555 | 556 | \n Type \q{(color-europe)} to get a color assignment. 557 | --------------------------------------------------------------------------------