heist 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt CHANGED
@@ -1,3 +1,20 @@
1
+ === Version 0.2.0 (2009-04-01)
2
+
3
+ The 'lists' release
4
+ * Entirely revised to correctly support lists as linked pairs
5
+ * Complete set of R5RS list functions
6
+ * Syntax for dotted pairs and improper lists implemented
7
+ * Rest-args for functions using dot notation
8
+ * Almost-complete R5RS numeric library, including complexes and rationals
9
+ * Some parser bugs regarding literals and quoting fixed
10
+ * Many macro parsing and expansion bugs fixed, esp. concerning nested repeating patterns
11
+ * Macro keywords and collisions with local variables now follow the spec
12
+ * R6RS ellipsis escaping feature -- (... ...) -- implemented
13
+ * All library syntax now implemented as macros, should all support call/cc
14
+ * Ruby data can now be executed as Scheme code
15
+ * Lots of inline documentation for the runtime
16
+
17
+
1
18
  === Version 0.1.0 (2009-02-25)
2
19
 
3
20
  First public release
data/Manifest.txt CHANGED
@@ -1,36 +1,36 @@
1
1
  History.txt
2
2
  Manifest.txt
3
- README.txt
4
3
  Rakefile
4
+ README.txt
5
5
  bin/heist
6
- lib/heist.rb
7
6
  lib/bin_spec.rb
7
+ lib/heist.rb
8
8
  lib/repl.rb
9
+ lib/builtin/library.scm
9
10
  lib/builtin/primitives.rb
10
- lib/builtin/syntax.rb
11
11
  lib/builtin/syntax.scm
12
- lib/builtin/library.scm
13
- lib/parser/scheme.tt
14
- lib/parser/scheme.rb
15
12
  lib/parser/nodes.rb
16
- lib/runtime/runtime.rb
17
- lib/runtime/data/expression.rb
18
- lib/runtime/data/identifier.rb
19
- lib/runtime/data/list.rb
13
+ lib/parser/ruby.rb
14
+ lib/parser/scheme.rb
15
+ lib/parser/scheme.tt
16
+ lib/runtime/callable/continuation.rb
20
17
  lib/runtime/callable/function.rb
18
+ lib/runtime/callable/syntax.rb
21
19
  lib/runtime/callable/macro.rb
22
20
  lib/runtime/callable/macro/matches.rb
23
- lib/runtime/callable/macro/splice.rb
21
+ lib/runtime/callable/macro/tree.rb
24
22
  lib/runtime/callable/macro/expansion.rb
25
- lib/runtime/callable/continuation.rb
26
- lib/runtime/stack.rb
27
- lib/runtime/stackless.rb
23
+ lib/runtime/data/cons.rb
24
+ lib/runtime/data/expression.rb
25
+ lib/runtime/data/identifier.rb
26
+ lib/runtime/binding.rb
28
27
  lib/runtime/frame.rb
28
+ lib/runtime/runtime.rb
29
29
  lib/runtime/scope.rb
30
- lib/runtime/binding.rb
30
+ lib/runtime/stack.rb
31
+ lib/runtime/stackless.rb
31
32
  lib/stdlib/benchmark.scm
32
33
  lib/stdlib/birdhouse.scm
33
- test/test_heist.rb
34
34
  test/arithmetic.scm
35
35
  test/benchmarks.scm
36
36
  test/booleans.scm
@@ -40,14 +40,18 @@ test/continuations.scm
40
40
  test/define_functions.scm
41
41
  test/define_values.scm
42
42
  test/delay.scm
43
+ test/equivalence.scm
43
44
  test/file_loading.scm
45
+ test/functional.scm
46
+ test/hygienic.scm
44
47
  test/let.scm
45
48
  test/lib.scm
49
+ test/lists.scm
46
50
  test/macro-helpers.scm
47
51
  test/macros.scm
48
- test/hygienic.scm
49
- test/unhygienic.scm
50
- test/plt-macros.txt
51
52
  test/numbers.scm
53
+ test/plt-macros.txt
54
+ test/test_heist.rb
55
+ test/unhygienic.scm
52
56
  test/vars.scm
53
57
 
data/README.txt CHANGED
@@ -33,51 +33,61 @@ languages.
33
33
 
34
34
  == Features
35
35
 
36
- Heist nominally targets R5RS and is still in the early stages of development
37
- (at time of writing it is about a month old). The priority at this stage
38
- is runtime support for features that cannot be directly expressed as
39
- Scheme functions. The library is therefore rather small but the runtime
40
- is more advanced than some other toy Schemes I've seen.
36
+ Heist nominally targets R5RS (http://www.schemers.org/Documents/Standards/R5RS/HTML).
37
+ It has good support for many Scheme runtime features such as tail call
38
+ optimisation, macros and first-class continuations, as well as reasonably
39
+ complete numeric and list libraries.
41
40
 
42
41
  Currently implemented R5RS features include:
43
42
 
44
43
  * Boolean literals: #t and #f
45
- * Numeric literals for integers, reals and rationals (though rationals
46
- are currently converted to floating point)
44
+ * Numeric literals for integers, reals, rationals and complexes. The
45
+ latter two are mapped to Ruby's <tt>Rational</tt> and <tt>Complex</tt>
46
+ objects and Ruby handles all math procedures.
47
47
  * String and symbol literals
48
- * Proper lists and full (quasi)quoting with <tt>'</tt>, <tt>`</tt>,
49
- <tt>,</tt>, <tt>,@</tt>
50
- * Macros: <tt>(syntax-rules)</tt>, <tt>(define-syntax)</tt>,
51
- <tt>(let-syntax)</tt>, <tt>(letrec-syntax)</tt>. Supports keywords,
52
- lists, pattern variables and ellipses down to arbitrary depth
53
- * Continuations: <tt>(call-with-current-continuation)</tt>, aliased
54
- as <tt>(call/cc)</tt>
48
+ * Proper and improper lists and full (quasi)quoting with <tt>'</tt>,
49
+ <tt>`</tt>, <tt>,</tt>, <tt>,@</tt>
50
+ * Macros: <tt>syntax-rules</tt>, <tt>define-syntax</tt>,
51
+ <tt>let-syntax</tt>, <tt>letrec-syntax</tt>. Supports keywords,
52
+ lists, pattern variables and ellipses down to arbitrary depth, as
53
+ well as the R6RS ellipsis-escaping feature (<tt>(... ...)</tt>) to
54
+ better enable macro-writing macros
55
+ * Continuations: <tt>call-with-current-continuation</tt>, aliased
56
+ as <tt>call/cc</tt>
55
57
  * Proper tail recursion
56
- * Variable assignment: <tt>(define)</tt> and <tt>(set!)</tt>
57
- * Lambda expressions: <tt>(lambda (x) body)</tt>, including lexical
58
- scoping and closures (varargs are currently not supported)
59
- * Control flow: <tt>(begin)</tt>, <tt>(if)</tt>, <tt>(cond)</tt>,
60
- <tt>(case)</tt>
61
- * Binding constructs: <tt>(let)</tt>, <tt>(let*)</tt>, <tt>(letrec)</tt>
62
- * Iteration: named <tt>(let)</tt>, <tt>(do)</tt>
63
- * Delayed evaluation: <tt>(delay)</tt> and <tt>(force)</tt>
64
- * Logical connectives: <tt>(and)</tt>, <tt>(or)</tt>, <tt>(not)</tt>
65
- * Type checking: <tt>(boolean?)</tt>, <tt>(number?)</tt>, <tt>(complex?)</tt>,
66
- <tt>(real?)</tt>, <tt>(rational?)</tt>, <tt>(integer?)</tt>
67
- * Comparators: <tt>(eqv?)</tt>, <tt>(=)</tt>, <tt>(<)</tt>, <tt>(<=)</tt>,
68
- <tt>(>)</tt>, <tt>(>=)</tt>
69
- * Numeric library: <tt>(max)</tt>, <tt>(min)</tt>, <tt>(+)</tt>,
70
- <tt>(-)</tt>, <tt>(*)</tt>, <tt>(/)</tt>, <tt>(quotient)</tt>,
71
- <tt>(remainder)</tt>, <tt>(modulo)</tt>, <tt>(floor)</tt>,
72
- <tt>(ceiling)</tt>, <tt>(truncate)</tt>, <tt>(round)</tt>,
73
- <tt>(exp)</tt>, <tt>(log)</tt>, <tt>(sin)</tt>, <tt>(cos)</tt>,
74
- <tt>(tan)</tt>, <tt>(asin)</tt>, <tt>(acos)</tt>, <tt>(atan)</tt>,
75
- <tt>(expt)</tt>, <tt>(sqrt)</tt>, <tt>(zero?)</tt>, <tt>(positive?)</tt>,
76
- <tt>(negative?)</tt>, <tt>(odd?)</tt>, <tt>(even?)</tt>, <tt>(abs)</tt>,
77
- <tt>(gcd)</tt>, <tt>(lcm)</tt>, <tt>(factorial)</tt>,
78
- <tt>(number->string)</tt>
79
- * String library: <tt>(display)</tt>, <tt>(newline)</tt>,
80
- <tt>(string->number)</tt>
58
+ * Variable assignment: <tt>define</tt> and <tt>set!</tt>
59
+ * Lambda expressions: <tt>(lambda (x ...) body ...)</tt>, including lexical
60
+ scoping and closures. Supports varargs using <tt>(lambda args body ...)</tt>
61
+ and <tt>(lambda (x y . rest) body ...)</tt> forms.
62
+ * Control flow: <tt>begin</tt>, <tt>if</tt>, <tt>cond</tt>,
63
+ <tt>case</tt>
64
+ * Binding constructs: <tt>let</tt>, <tt>let*</tt>, <tt>letrec</tt>
65
+ * Iteration: named <tt>let</tt>, <tt>do</tt>
66
+ * Delayed evaluation: <tt>delay</tt> and <tt>force</tt>
67
+ * Logical connectives: <tt>and</tt>, <tt>or</tt>, <tt>not</tt>
68
+ * Type checking: <tt>boolean?</tt>, <tt>number?</tt>, <tt>complex?</tt>,
69
+ <tt>real?</tt>, <tt>rational?</tt>, <tt>integer?</tt>, <tt>exact?</tt>,
70
+ <tt>inexact?</tt>, <tt>symbol?</tt>, <tt>string?</tt>, <tt>pair?</tt>,
71
+ <tt>list?</tt>, <tt>null?</tt>, <tt>procedure?</tt>
72
+ * Comparators: <tt>eq?</tt>, <tt>eqv?</tt>, <tt>equal?</tt>, <tt>=</tt>,
73
+ <tt><</tt>, <tt><=</tt>, <tt>></tt>, <tt>>=</tt>
74
+ * Numeric library: <tt>max</tt>, <tt>min</tt>, <tt>+</tt>, <tt>-</tt>,
75
+ <tt>*</tt>, <tt>/</tt>, <tt>quotient</tt>, <tt>remainder</tt>,
76
+ <tt>modulo</tt>, <tt>numerator</tt>, <tt>denominator</tt>, <tt>floor</tt>,
77
+ <tt>ceiling</tt>, <tt>truncate</tt>, <tt>round</tt>, <tt>exp</tt>,
78
+ <tt>log</tt>, <tt>sin</tt>, <tt>cos</tt>, <tt>tan</tt>, <tt>asin</tt>,
79
+ <tt>acos</tt>, <tt>atan</tt>, <tt>expt</tt>, <tt>sqrt</tt>,
80
+ <tt>zero?</tt>, <tt>positive?</tt>, <tt>negative?</tt>, <tt>odd?</tt>,
81
+ <tt>even?</tt>, <tt>abs</tt>, <tt>gcd</tt>, <tt>lcm</tt>,
82
+ <tt>make-rectangular</tt>, <tt>make-polar</tt>, <tt>real-part</tt>,
83
+ <tt>imag-part</tt>, <tt>magnitude</tt>, <tt>angle</tt>, <tt>factorial</tt>,
84
+ <tt>number->string</tt>
85
+ * List library: <tt>cons</tt>, <tt>car</tt>, <tt>cdr</tt>, <tt>set-car!</tt>,
86
+ <tt>set-cdr!</tt>, <tt>c[ad]{1,4}r</tt>, <tt>list</tt>, <tt>length</tt>,
87
+ <tt>append</tt>, <tt>reverse</tt>, <tt>list-tail</tt>, <tt>list-ref</tt>,
88
+ <tt>memq</tt>, <tt>memv</tt>, <tt>member</tt>, <tt>assq</tt>, <tt>assv</tt>,
89
+ <tt>assoc</tt>, <tt>apply</tt>, <tt>map</tt>, <tt>for-each</tt>
90
+ * String library: <tt>display</tt>, <tt>newline</tt>, <tt>string->number</tt>
81
91
  * File loading: <tt>(load "foo.scm")</tt>, paths are relative to the
82
92
  current file
83
93
 
@@ -120,6 +130,9 @@ To start an REPL session:
120
130
  Both these commands accept a number of runtime configuration options;
121
131
  run <tt>heist -h</tt> for more information.
122
132
 
133
+
134
+ === Embed in your Ruby app
135
+
123
136
  To embed Heist in a Ruby application, you need to create an instance of
124
137
  the runtime:
125
138
 
@@ -146,6 +159,13 @@ compatible; enabling continuations forces eager evaluation. Also
146
159
  note that lazy evaluation has a slightly unpredictable effect on the
147
160
  use of macros.
148
161
 
162
+ To run a Scheme file using the runtime, just call:
163
+
164
+ scheme.run("path/to/file.scm")
165
+
166
+
167
+ === Create Scheme functions using Ruby
168
+
149
169
  Every runtime gets its own copy of all the built-in functions. You can add
150
170
  your own functions written in Ruby and Heist will make them available as
151
171
  Scheme procedures. For example, for running tests I do this in my +setup+
@@ -160,9 +180,28 @@ This lets me write, for example, <tt>(assert-equal 7 (+ 3 4))</tt> in my
160
180
  tests. You can place arbitrary Ruby code in your functions, so this is
161
181
  an easy way to expose Ruby functionality to the Scheme environment.
162
182
 
163
- To run a Scheme file using the runtime, just call:
164
183
 
165
- scheme.run("path/to/file.scm")
184
+ === Run Ruby data as Scheme code
185
+
186
+ Heist can interpret Scheme code provided as Ruby data, allowing you
187
+ to write and manipulate Lisp-style expressions inline with Ruby code.
188
+ For example, using our <tt>Heist::Runtime</tt> instance from above:
189
+
190
+ scheme.exec [:define, [:square, :x], [:*, :x, :x]]
191
+
192
+ scheme.exec [:square, 9]
193
+ #=> 81
194
+
195
+ Arrays map directly to Scheme lists, symbols map to identifiers, strings
196
+ and numbers are treated as literals, and any other data is interpreted
197
+ verbatim. So, you can use any piece of Ruby data in these expressions
198
+ as long as the functions you're calling can operate on it.
199
+
200
+ Due to syntactic limitations, some Scheme syntax cannot be used in this
201
+ interface. Quoting is out, so the expression <tt>'(1 2 3)</tt> would
202
+ need to be written <tt>[:quote, [1, 2, 3]]</tt>. Dotted pairs and
203
+ improper lists are also not available, though you can work around
204
+ this to some extent using <tt>:cons</tt>.
166
205
 
167
206
 
168
207
  == Notes
@@ -184,13 +223,6 @@ is not a boolean literal, a number or a string is considered a valid
184
223
  symbol. This means that syntax that should be used for chars and
185
224
  vectors will currently parse as symbols.
186
225
 
187
- There are currently no list operations. This may seem like a
188
- staggering omission but my goal initially was to work through the
189
- early stages of SICP, for which Heist in its current form is
190
- adequate. Being something of a simpleton, I wrote the list representation
191
- using arrays and it will need gutting and converting to linked lists
192
- before list operations are implemented.
193
-
194
226
  Macros are slightly more liberal than R5RS, in that this is a valid
195
227
  macro:
196
228
 
@@ -202,10 +234,10 @@ macro:
202
234
  You are allowed to use ellipses in infix positions, as long as the
203
235
  pattern that follows the ellipsis matches input that the preceeding
204
236
  pattern would fail to match. This is, the ellipsis acts as a greedy
205
- star operator in regular expressions. In the above, <tt>(name value) ...</tt>
206
- captures input until a non-list expression is met, at which point
207
- <tt>body ...</tt> takes over. The following expression evaluates
208
- to <tt>3</tt> using this macro:
237
+ star operator in regular expressions. In the above, <tt>(name value) ... body ...</tt>
238
+ matches zero or more two-element lists followed by zero or more
239
+ expressions of any type. The following expression evaluates to
240
+ <tt>3</tt> using this macro:
209
241
 
210
242
  (my-let (x 2) (y 3) y)
211
243
 
@@ -2,11 +2,36 @@
2
2
  ; in Scheme should go here. If at all possible, write
3
3
  ; builtins in Scheme rather than Ruby.
4
4
 
5
+ ; (newline)
6
+ ; prints a new-line character
7
+ (define (newline)
8
+ (display "\n"))
9
+
10
+ ; (force)
11
+ ; Extracts the value of a promise created using (delay)
12
+ (define (force promise) (promise))
13
+
14
+ ; (call/cc)
15
+ ; Alias for (call-with-current-continuation)
16
+ (define call/cc call-with-current-continuation)
17
+
18
+ ; (eq? x y)
19
+ ; Currently an alias for (eqv? x y). TODO implement properly
20
+ (define eq? eqv?)
21
+
5
22
  ; (not x)
6
23
  ; Boolean inverse of x
7
24
  (define (not x)
8
25
  (if x #f #t))
9
26
 
27
+ ; (negate x)
28
+ ; Returns a negated form of x, like (not) but also
29
+ ; works on functions
30
+ (define (negate proc)
31
+ (if (procedure? proc)
32
+ (lambda args (not (apply proc args)))
33
+ (not proc)))
34
+
10
35
  ; Longhand aliases for boolean constants
11
36
  (define true #t)
12
37
  (define false #f)
@@ -16,10 +41,18 @@
16
41
  (define (boolean? x)
17
42
  (or (eqv? x #t) (eqv? x #f)))
18
43
 
44
+ ;----------------------------------------------------------------
45
+
46
+ ; Numerical functions
47
+
19
48
  ; (number? x)
20
49
  ; Returns true iff x is any type of number
21
50
  (define number? complex?)
22
51
 
52
+ ; (inexact? x)
53
+ ; Returns true iff x is not an exact number
54
+ (define inexact? (negate exact?))
55
+
23
56
  ; (zero? x)
24
57
  ; Returns true iff x is zero
25
58
  (define (zero? x)
@@ -45,6 +78,20 @@
45
78
  (define (even? x)
46
79
  (zero? (remainder x 2)))
47
80
 
81
+ ; (max arg1 arg2 ...)
82
+ ; Returns the maximum value in the list of arguments
83
+ (define (max . values)
84
+ (foldr (lambda (a b) (if (>= a b) a b))
85
+ (car values)
86
+ (cdr values)))
87
+
88
+ ; (min arg1 arg2 ...)
89
+ ; Returns the minimum value in the list of arguments
90
+ (define (min . values)
91
+ (foldr (lambda (a b) (if (<= a b) a b))
92
+ (car values)
93
+ (cdr values)))
94
+
48
95
  ; (abs x)
49
96
  ; Returns the absolute value of a number
50
97
  (define (abs x)
@@ -71,6 +118,29 @@
71
118
 
72
119
  (define ceiling ceil)
73
120
 
121
+ ; (make-polar magnitude angle)
122
+ ; Returns a new complex number with the given
123
+ ; magnitude and angle
124
+ (define (make-polar magnitude angle)
125
+ (let ([re (* magnitude (cos angle))]
126
+ [im (* magnitude (sin angle))])
127
+ (make-rectangular re im)))
128
+
129
+ ; (magnitude z)
130
+ ; Returns the magnitude of a complex number
131
+ (define (magnitude z)
132
+ (let ([re (real-part z)]
133
+ [im (imag-part z)])
134
+ (sqrt (+ (* re re) (* im im)))))
135
+
136
+ ; (angle z)
137
+ ; Returns the angle a complex number makes with the
138
+ ; real axis when plotted in the complex plane
139
+ (define (angle z)
140
+ (let ([re (real-part z)]
141
+ [im (imag-part z)])
142
+ (atan im re)))
143
+
74
144
  ; (factorial x)
75
145
  ; Returns factorial of x
76
146
  (define (factorial x)
@@ -80,16 +150,144 @@
80
150
  (iter (- y 1) (* y acc))))
81
151
  (iter x 1))
82
152
 
83
- ; (newline)
84
- ; prints a new-line character
85
- (define (newline)
86
- (display "\n"))
153
+ ;----------------------------------------------------------------
87
154
 
88
- ; (force)
89
- ; Extracts the value of a promise created using (delay)
90
- (define (force promise) (promise))
155
+ ; List/pair functions
91
156
 
92
- ; (call/cc)
93
- ; Alias for (call-with-current-continuation)
94
- (define call/cc call-with-current-continuation)
157
+ ; (null? object)
158
+ ; Returns true iff object is the empty list
159
+ (define (null? object)
160
+ (eqv? '() object))
161
+
162
+ ; (list? object)
163
+ ; Returns true iff object is a proper list
164
+ (define (list? object)
165
+ (or (null? object)
166
+ (and (pair? object)
167
+ (list? (cdr object)))))
168
+
169
+ ; (list arg ...)
170
+ ; Allocates and returns a new list from its arguments
171
+ (define (list . args) args)
172
+
173
+ ; (length object)
174
+ ; Returns the length of a proper list
175
+ (define (length object)
176
+ (define (iter list acc)
177
+ (if (null? list)
178
+ acc
179
+ (iter (cdr list) (+ 1 acc))))
180
+ (iter object 0))
181
+
182
+ ; (append list ...)
183
+ ; Returns a new list formed by concatenating the arguments.
184
+ ; The final argument is not copied and the return value of
185
+ ; (append) shares structure with it.
186
+ (define (append first . rest)
187
+ (if (null? first)
188
+ (apply append rest)
189
+ (if (null? rest)
190
+ first
191
+ (let ([copy (apply list first)])
192
+ (do ([pair copy (cdr pair)])
193
+ ((null? (cdr pair))
194
+ (set-cdr! pair (apply append rest))))
195
+ copy))))
196
+
197
+ ; (reverse list)
198
+ ; Returns a newly allocated list consisting of the
199
+ ; elements of list in reverse order.
200
+ (define (reverse object)
201
+ (if (null? object)
202
+ object
203
+ (append (reverse (cdr object))
204
+ (list (car object)))))
205
+
206
+ ; (list-tail list k)
207
+ ; Returns the sublist of list obtained by omitting the
208
+ ; first k elements.
209
+ (define (list-tail list k)
210
+ (do ([pair list (cdr pair)]
211
+ [i k (- i 1)])
212
+ ((zero? i) pair)))
213
+
214
+ ; (list-ref list k)
215
+ ; Returns the kth element of list.
216
+ (define (list-ref list k)
217
+ (car (list-tail list k)))
218
+
219
+ ; (memq obj list)
220
+ ; (memv obj list)
221
+ ; (member obj list)
222
+ ; These procedures return the first sublist of list whose
223
+ ; car is obj, where the sublists of list are the non-empty
224
+ ; lists returned by (list-tail list k) for k less than the
225
+ ; length of list. If obj does not occur in list, then #f
226
+ ; (not the empty list) is returned. Memq uses eq? to compare
227
+ ; obj with the elements of list, while memv uses eqv? and
228
+ ; member uses equal?.
229
+
230
+ (define (list-transform-search transform)
231
+ (lambda (predicate)
232
+ (lambda (object list)
233
+ (do ([pair list (cdr pair)])
234
+ ((or (null? pair)
235
+ (predicate (car (transform pair)) object))
236
+ (if (null? pair)
237
+ #f
238
+ (transform pair)))))))
239
+
240
+ (define list-search (list-transform-search (lambda (x) x)))
241
+ (define memq (list-search eq?))
242
+ (define memv (list-search eqv?))
243
+ (define member (list-search equal?))
244
+
245
+ ; (assq obj alist)
246
+ ; (assv obj alist)
247
+ ; (assoc obj alist)
248
+ ; Alist (for "association list") must be a list of pairs.
249
+ ; These procedures find the first pair in alist whose car
250
+ ; field is obj, and returns that pair. If no pair in alist
251
+ ; has obj as its car, then #f (not the empty list) is
252
+ ; returned. Assq uses eq? to compare obj with the car fields
253
+ ; of the pairs in alist, while assv uses eqv? and assoc
254
+ ; uses equal?.
255
+
256
+ (define assoc-list-search (list-transform-search car))
257
+ (define assq (assoc-list-search eq?))
258
+ (define assv (assoc-list-search eqv?))
259
+ (define assoc (assoc-list-search equal?))
260
+
261
+ ; (map proc list1 list2 ...)
262
+ ; Returns a new list formed by applying proc to each member
263
+ ; (or set of members) of the given list(s).
264
+ (define (map proc list1 . list2)
265
+ (if (null? list1)
266
+ list1
267
+ (if (null? list2)
268
+ (cons (proc (car list1))
269
+ (map proc (cdr list1)))
270
+ (let* ([all (cons list1 list2)]
271
+ [args (map car all)]
272
+ [rest (map cdr all)])
273
+ (cons (apply proc args)
274
+ (apply map (cons proc rest)))))))
275
+
276
+ ; (for-each proc list1 list2 ...)
277
+ ; Calls proc once for each member of list1, passing each
278
+ ; member (or set of members if more than one list given)
279
+ ; as arguments to proc.
280
+ (define (for-each proc list1 . list2)
281
+ (do ([pair list1 (cdr pair)]
282
+ [others list2 (map cdr others)])
283
+ ((null? pair) '())
284
+ (apply proc (cons (car pair)
285
+ (map car others)))))
286
+
287
+ ; (foldr proc value list)
288
+ (define (foldr proc value list)
289
+ (if (null? list)
290
+ value
291
+ (proc (car list)
292
+ (foldr proc value (cdr list)))))
95
293