-
Notifications
You must be signed in to change notification settings - Fork 19
/
dialect.tex
304 lines (244 loc) · 8.38 KB
/
dialect.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
% last change: 2020-11-13
\chapter{Scheme dialects}
\label{dialect}
\index{dialects of Scheme}
\index{R5RS}
All major Scheme dialects implement the R5RS
specification \cite{r5rs}. By using only the features
documented in the R5RS, one can write Scheme code that
is portable across the dialects. However, the R5RS,
either for want of consensus or because of inevitable
system dependencies, remains silent on several matters
that non-trivial programming cannot ignore. The
various dialects have therefore had to solve these
matters in a non-standard and idiosyncratic manner.
\index{MzScheme}
This book uses the MzScheme \cite{mzscheme}
dialect of Scheme, and thereby uses several
features that are nonstandard. The complete
list of the dialect-dependent features used
in this book is: the command-line (both for
opening a listener session and for shell scripts),
\q{define-macro}, \q{delete-file}, \q{file-exists?},
\q{file-or-directory-modify-seconds}, \q{fluid-let},
\q{gensym}, \q{getenv}, \q{get-output-string},
\q{load-relative}, \q{open-input-string},
\q{open-output-string}, \q{read-line}, \q{reverse!},
\q{system}, \q{unless} and \q{when}.
All but two of these
are present in the default environment of MzScheme. The missing two,
\q{define-macro} and \q{system}, are provided in
standard MzScheme libraries, which can be explicitly loaded into
MzScheme using the forms:
\q{
(require (lib "defmacro.ss")) ;provides define-macro
(require (lib "process.ss")) ;provides system
}
\n A good place to place these forms is the MzScheme
{\em initialization file} (or {\em init file}), which, on Unix, is the file
\p{.mzschemerc} in the user’s home directory.\f{We will
use \p{~/filename} to denote the file called
\p{filename} in the user’s home directory.}
Some of the nonstandard features (e.g., \q{file-exists?},
\q{delete-file}) are in fact de facto standards and are present
in many Schemes. Some other features (e.g., \q{when},
\q{unless}) have more or less “plug-in” definitions
(given in this book) that can be loaded into any Scheme
dialect that doesn’t have them primitively. The rest
require a dialect-specific definition
(e.g., \q{load-relative}).
This chapter describes how to incorporate into your
Scheme dialect the nonstandard features used in this
book. For further detail about your Scheme
dialect, consult the documentation provided by its
implementor (appendix~\ref{references}).
\iffalse
\section{Invocation and init files}
\index{Guile}
\index{SCM}
\index{STk}
To invoke the Guile \cite{guile} listener, type \p{guile}. To invoke
SCM \cite{scm}, type \p{scm}.
To invoke STk \cite{stk}, type \p{snow}. This is the
“no window” executable, which is enough for the purposes
of this book.
\fi
\index{init file}
\section{Invocation and init files}
\index{file-or-directory-modify-seconds@\q{file-or-directory-modify-seconds}}
\index{Guile}
Like MzScheme, many Scheme dialects load, if
available, an init file, usually supplied in the user’s
home directory. The init file is a convenient location
in which to place definitions for nonstandard features.
E.g., the nonstandard procedure
\q{file-or-directory-modify-seconds} can be added to
the Guile~\cite{guile} dialect of Scheme by putting the
following code in Guile’s init file, which is
\p{~/.guile}:
\q{
(define file-or-directory-modify-seconds
(lambda (f)
(vector-ref (stat f) 9)))
}
Also, the various Scheme dialects have their own
distinctively named commands to invoke their respective
listeners. The following
table lists the invoking commands and init files
for some Scheme dialects:
\halign{\qquad \hfil # & # & # \cr
{\em Dialect name} & {\em Command} & {\em Init~file} \cr
Bigloo & \p{bigloo} & \p{~/.bigloorc} \cr
Chicken & \p{csi} & \p{~/.csirc} \cr
Gambit & \p{gsi} & \p{~/gambc.scm} \cr
Gauche & \p{gosh} & \p{~/.gaucherc} \cr
Guile & \p{guile} & \p{~/.guile} \cr
Kawa & \p{kawa} & \p{~/.kawarc.scm} \cr
MIT Scheme (Unix) & \p{scheme} & \p{~/.scheme.init} \cr
MIT Scheme (Win) & \p{scheme} & \p{~/scheme.ini} \cr
MzScheme (Unix, Mac OS X) & \p{mzscheme} & \p{~/.mzschemerc} \cr
MzScheme (Win, Mac OS Classic) & \p{mzscheme} & \p{~/mzschemerc.ss} \cr
SCM & \p{scm} & \p{~/ScmInit.scm} \cr
STk & \p{snow} & \p{~/.stkrc} \cr
}
\iffalse
Note, however, that for the purposes of this text, you
don’t need to insert code into \p{~/.mzschemerc},
since we don’t use any nonstandard Scheme feature not
already defined in MzScheme.
\fi
\index{script}
\section{Shell scripts}
The initial line for a shell script written in Guile is:
\q{
":";exec guile -s $0 "$@"
}
In the script, the procedure-call \q{(command-line)} returns
the list of the script’s name and arguments. To access
just the arguments, take the \q{cdr} of this list.
A Gauche~\cite{gauche} shell script starts out as:
\q{
":"; exec gosh -- $0 "$@"
}
In the script, the variable \q{*argv*} holds
the list of the script’s arguments.
A shell script written in SCM starts out as:
\q{
":";exec scm -l $0 "$@"
}
In the script, the variable \q{*argv*} contains
the list of the Scheme executable name, the script’s
name, the option \p{-l}, and the script’s arguments.
To
access just the arguments, take the \q{cdddr} of this list.
STk~\cite{stk} shell scripts start out as:
\q{
":";exec snow -f $0 "$@"
}
In the script, the variable \q{*argv*} contains
the list of the script’s arguments.
\index{define-macro@\q{define-macro}!in various dialects}
\section{\q{define-macro}}
\label{dialect-macro}
\index{Bigloo}\index{Chicken}
\index{Gambit}\index{Gauche}\index{Pocket Scheme}
The \q{define-macro} used in the text occurs in
the Scheme dialects Bigloo \cite{bigloo},
Chicken~\cite{chicken}, Gambit
\cite{gambit}, Gauche~\cite{gauche}, Guile, MzScheme and Pocket Scheme
\cite{pocketscheme}. There are minor variations in
how macros are defined in the other Scheme dialects.
The rest of this section will point out how these
other dialects notate the following code fragment:
\q{
(define-macro MACRO-NAME
(lambda MACRO-ARGS
MACRO-BODY ...))
}
\index{MIT Scheme}
\n In MIT Scheme~\cite{mitscheme} version 7.7.1 and later, this is written as:
\q{
(define-syntax MACRO-NAME
(rsc-macro-transformer
(let ((xfmr (lambda MACRO-ARGS MACRO-BODY ...)))
(lambda (e r)
(apply xfmr (cdr e))))))
}
\n In older versions of MIT Scheme:
\q{
(syntax-table-define system-global-syntax-table 'MACRO-NAME
(macro MACRO-ARGS
MACRO-BODY ...))
}
\index{Kawa}
\index{SCM}
\n In SCM~\cite{scm} and Kawa \cite{kawa}:
\q{
(defmacro MACRO-NAME MACRO-ARGS
MACRO-BODY ...)
}
\index{STk}
\n In STk~\cite{stk}:
\q{
(define-macro (MACRO-NAME . MACRO-ARGS)
MACRO-BODY ...)
}
\index{load-relative@\q{load-relative}!in various dialects}
\section{\q{load-relative}}
The procedure \q{load-relative} may be defined for Guile as follows:
\q{
(define load-relative
(lambda (f)
(let* ((n (string-length f))
(full-pathname?
(and (> n 0)
(let ((c0 (string-ref f 0)))
(or (char=? c0 #\/)
(char=? c0 #\~))))))
(basic-load
(if full-pathname? f
(let ((clp (current-load-port)))
(if clp
(string-append
(dirname (port-filename clp)) "/" f)
f)))))))
}
For SCM:
\q{
(define load-relative
(lambda (f)
(let* ((n (string-length f))
(full-pathname?
(and (> n 0)
(let ((c0 (string-ref f 0)))
(or (char=? c0 #\/)
(char=? c0 #\~))))))
(load (if (and *load-pathname* full-pathname?)
(in-vicinity (program-vicinity) f)
f)))))
}
For STk, the following definition for \q{load-relative}
works only if you discipline yourself to not use \q{load}:
\q{
(define *load-pathname* #f)
(define stk%load load)
(define load-relative
(lambda (f)
(fluid-let
((*load-pathname*
(if (not *load-pathname*) f
(let* ((n (string-length f))
(full-pathname?
(and (> n 0)
(let ((c0 (string-ref f 0)))
(or (char=? c0 #\/)
(char=? c0 #\~))))))
(if full-pathname? f
(string-append
(dirname *load-pathname*)
"/" f))))))
(stk%load *load-pathname*))))
(define load
(lambda (f)
(error "Don’t use load. Use load-relative instead.")))
}