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 +17 -0
- data/Manifest.txt +23 -19
- data/README.txt +84 -52
- data/lib/builtin/library.scm +208 -10
- data/lib/builtin/primitives.rb +154 -92
- data/lib/builtin/syntax.scm +22 -5
- data/lib/heist.rb +49 -17
- data/lib/parser/nodes.rb +47 -24
- data/lib/parser/ruby.rb +29 -0
- data/lib/parser/scheme.rb +455 -143
- data/lib/parser/scheme.tt +23 -5
- data/lib/repl.rb +19 -16
- data/lib/runtime/binding.rb +24 -2
- data/lib/runtime/callable/continuation.rb +23 -2
- data/lib/runtime/callable/function.rb +122 -21
- data/lib/runtime/callable/macro.rb +169 -123
- data/lib/runtime/callable/macro/expansion.rb +137 -2
- data/lib/runtime/callable/macro/matches.rb +125 -41
- data/lib/runtime/callable/macro/tree.rb +141 -0
- data/lib/runtime/callable/syntax.rb +44 -0
- data/lib/runtime/data/cons.rb +234 -0
- data/lib/runtime/data/expression.rb +15 -6
- data/lib/runtime/data/identifier.rb +19 -2
- data/lib/runtime/frame.rb +102 -35
- data/lib/runtime/runtime.rb +44 -19
- data/lib/runtime/scope.rb +145 -30
- data/lib/runtime/stack.rb +103 -1
- data/lib/runtime/stackless.rb +48 -6
- data/test/arithmetic.scm +11 -2
- data/test/continuations.scm +16 -2
- data/test/equivalence.scm +34 -0
- data/test/functional.scm +4 -0
- data/test/lists.scm +78 -0
- data/test/macro-helpers.scm +1 -0
- data/test/macros.scm +111 -24
- data/test/numbers.scm +30 -8
- data/test/test_heist.rb +67 -12
- metadata +25 -21
- data/lib/builtin/syntax.rb +0 -166
- data/lib/runtime/callable/macro/splice.rb +0 -56
- data/lib/runtime/data/list.rb +0 -36
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/
|
17
|
-
lib/
|
18
|
-
lib/
|
19
|
-
lib/runtime/
|
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/
|
21
|
+
lib/runtime/callable/macro/tree.rb
|
24
22
|
lib/runtime/callable/macro/expansion.rb
|
25
|
-
lib/runtime/
|
26
|
-
lib/runtime/
|
27
|
-
lib/runtime/
|
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/
|
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
|
37
|
-
|
38
|
-
|
39
|
-
|
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
|
46
|
-
are
|
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>,
|
49
|
-
<tt>,</tt>, <tt>,@</tt>
|
50
|
-
* Macros: <tt>
|
51
|
-
<tt>
|
52
|
-
lists, pattern variables and ellipses down to arbitrary depth
|
53
|
-
|
54
|
-
|
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>
|
57
|
-
* Lambda expressions: <tt>(lambda (x) body)</tt>, including lexical
|
58
|
-
scoping and closures
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
*
|
63
|
-
*
|
64
|
-
*
|
65
|
-
*
|
66
|
-
|
67
|
-
|
68
|
-
<tt>
|
69
|
-
|
70
|
-
|
71
|
-
<tt
|
72
|
-
|
73
|
-
<tt
|
74
|
-
<tt>
|
75
|
-
<tt>
|
76
|
-
<tt>
|
77
|
-
<tt>
|
78
|
-
<tt>
|
79
|
-
|
80
|
-
<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
|
-
|
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
|
-
|
207
|
-
|
208
|
-
|
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
|
|
data/lib/builtin/library.scm
CHANGED
@@ -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
|
-
|
84
|
-
; prints a new-line character
|
85
|
-
(define (newline)
|
86
|
-
(display "\n"))
|
153
|
+
;----------------------------------------------------------------
|
87
154
|
|
88
|
-
;
|
89
|
-
; Extracts the value of a promise created using (delay)
|
90
|
-
(define (force promise) (promise))
|
155
|
+
; List/pair functions
|
91
156
|
|
92
|
-
; (
|
93
|
-
;
|
94
|
-
(define
|
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
|
|