heist 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +21 -0
- data/Manifest.txt +53 -0
- data/README.txt +274 -0
- data/Rakefile +12 -0
- data/bin/heist +16 -0
- data/lib/bin_spec.rb +25 -0
- data/lib/builtin/library.scm +95 -0
- data/lib/builtin/primitives.rb +306 -0
- data/lib/builtin/syntax.rb +166 -0
- data/lib/builtin/syntax.scm +155 -0
- data/lib/heist.rb +47 -0
- data/lib/parser/nodes.rb +105 -0
- data/lib/parser/scheme.rb +1081 -0
- data/lib/parser/scheme.tt +80 -0
- data/lib/repl.rb +112 -0
- data/lib/runtime/binding.rb +31 -0
- data/lib/runtime/callable/continuation.rb +24 -0
- data/lib/runtime/callable/function.rb +55 -0
- data/lib/runtime/callable/macro.rb +170 -0
- data/lib/runtime/callable/macro/expansion.rb +15 -0
- data/lib/runtime/callable/macro/matches.rb +77 -0
- data/lib/runtime/callable/macro/splice.rb +56 -0
- data/lib/runtime/data/expression.rb +23 -0
- data/lib/runtime/data/identifier.rb +20 -0
- data/lib/runtime/data/list.rb +36 -0
- data/lib/runtime/frame.rb +118 -0
- data/lib/runtime/runtime.rb +61 -0
- data/lib/runtime/scope.rb +121 -0
- data/lib/runtime/stack.rb +60 -0
- data/lib/runtime/stackless.rb +49 -0
- data/lib/stdlib/benchmark.scm +12 -0
- data/lib/stdlib/birdhouse.scm +82 -0
- data/test/arithmetic.scm +57 -0
- data/test/benchmarks.scm +27 -0
- data/test/booleans.scm +6 -0
- data/test/closures.scm +16 -0
- data/test/conditionals.scm +55 -0
- data/test/continuations.scm +144 -0
- data/test/define_functions.scm +27 -0
- data/test/define_values.scm +28 -0
- data/test/delay.scm +8 -0
- data/test/file_loading.scm +9 -0
- data/test/hygienic.scm +39 -0
- data/test/let.scm +42 -0
- data/test/lib.scm +2 -0
- data/test/macro-helpers.scm +19 -0
- data/test/macros.scm +343 -0
- data/test/numbers.scm +19 -0
- data/test/plt-macros.txt +40 -0
- data/test/test_heist.rb +84 -0
- data/test/unhygienic.scm +11 -0
- data/test/vars.scm +2 -0
- metadata +138 -0
data/History.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
=== Version 0.1.0 (2009-02-25)
|
2
|
+
|
3
|
+
First public release
|
4
|
+
* Data: booleans, numbers, strings, symbols, proper lists
|
5
|
+
* Most of R5RS syntax (chapter 4)
|
6
|
+
* Quoting, quasiquoting
|
7
|
+
* Binding constructs, conditionals
|
8
|
+
* Boolean logic
|
9
|
+
* Delayed evaluation
|
10
|
+
* Macros
|
11
|
+
* Tail recursion
|
12
|
+
* Continuations
|
13
|
+
* Optional transparent lazy evaluation
|
14
|
+
* Decent chunk of R5RS numeric library
|
15
|
+
|
16
|
+
|
17
|
+
=== Version 0 (2009-01-12)
|
18
|
+
|
19
|
+
Initial draft. Supports (define), (lambda), lexical scoping,
|
20
|
+
closures, arithmetic and (display).
|
21
|
+
|
data/Manifest.txt
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
bin/heist
|
6
|
+
lib/heist.rb
|
7
|
+
lib/bin_spec.rb
|
8
|
+
lib/repl.rb
|
9
|
+
lib/builtin/primitives.rb
|
10
|
+
lib/builtin/syntax.rb
|
11
|
+
lib/builtin/syntax.scm
|
12
|
+
lib/builtin/library.scm
|
13
|
+
lib/parser/scheme.tt
|
14
|
+
lib/parser/scheme.rb
|
15
|
+
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
|
20
|
+
lib/runtime/callable/function.rb
|
21
|
+
lib/runtime/callable/macro.rb
|
22
|
+
lib/runtime/callable/macro/matches.rb
|
23
|
+
lib/runtime/callable/macro/splice.rb
|
24
|
+
lib/runtime/callable/macro/expansion.rb
|
25
|
+
lib/runtime/callable/continuation.rb
|
26
|
+
lib/runtime/stack.rb
|
27
|
+
lib/runtime/stackless.rb
|
28
|
+
lib/runtime/frame.rb
|
29
|
+
lib/runtime/scope.rb
|
30
|
+
lib/runtime/binding.rb
|
31
|
+
lib/stdlib/benchmark.scm
|
32
|
+
lib/stdlib/birdhouse.scm
|
33
|
+
test/test_heist.rb
|
34
|
+
test/arithmetic.scm
|
35
|
+
test/benchmarks.scm
|
36
|
+
test/booleans.scm
|
37
|
+
test/closures.scm
|
38
|
+
test/conditionals.scm
|
39
|
+
test/continuations.scm
|
40
|
+
test/define_functions.scm
|
41
|
+
test/define_values.scm
|
42
|
+
test/delay.scm
|
43
|
+
test/file_loading.scm
|
44
|
+
test/let.scm
|
45
|
+
test/lib.scm
|
46
|
+
test/macro-helpers.scm
|
47
|
+
test/macros.scm
|
48
|
+
test/hygienic.scm
|
49
|
+
test/unhygienic.scm
|
50
|
+
test/plt-macros.txt
|
51
|
+
test/numbers.scm
|
52
|
+
test/vars.scm
|
53
|
+
|
data/README.txt
ADDED
@@ -0,0 +1,274 @@
|
|
1
|
+
= Heist
|
2
|
+
|
3
|
+
Heist is a Scheme interpreter written in Ruby. It provides an executable
|
4
|
+
for running Scheme code directly, and also allows the interpreter to be
|
5
|
+
easily embedded in, and extended using, Ruby applications. It nominally
|
6
|
+
targets R5RS, though is likely to be more liberal than other implementations.
|
7
|
+
|
8
|
+
|
9
|
+
== What is Scheme?
|
10
|
+
|
11
|
+
Scheme is a dialect of Lisp, one of the oldest programming languages still
|
12
|
+
in use today. Lisp was the first language to implement conditionals, first
|
13
|
+
class functions (lambdas), closures and recursion. Some Lisp features, such
|
14
|
+
as closures and macros, have yet to penetrate mainstream languages and it
|
15
|
+
has been observed that mainstream languages are slowly converging on the
|
16
|
+
feature set of Lisp.
|
17
|
+
|
18
|
+
Scheme in particular is important for its influence on current languages,
|
19
|
+
in particular JavaScript and Ruby (JavaScript is remarkably similar to
|
20
|
+
Scheme if you ignore the syntactic differences). It is also used in the
|
21
|
+
much-praised book "Structure and Interpretation of Computer Programs",
|
22
|
+
wherein it is used to explore some of the theory surrounding interpreters.
|
23
|
+
|
24
|
+
It is a functional language, in that it supports first-class functions
|
25
|
+
and many constructs that would be syntax in other languages resemble
|
26
|
+
function calls in Scheme. However it is not purely functional as it
|
27
|
+
allows side effects, and is more procedural in nature than, say, a
|
28
|
+
declarative language such as Haskell. Like other Lisps, its lack of
|
29
|
+
predefined syntax and its support for macros (functions that rewrite
|
30
|
+
source code) make it ideal for creating new syntactic forms and embedded
|
31
|
+
languages.
|
32
|
+
|
33
|
+
|
34
|
+
== Features
|
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.
|
41
|
+
|
42
|
+
Currently implemented R5RS features include:
|
43
|
+
|
44
|
+
* Boolean literals: #t and #f
|
45
|
+
* Numeric literals for integers, reals and rationals (though rationals
|
46
|
+
are currently converted to floating point)
|
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>
|
55
|
+
* 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>
|
81
|
+
* File loading: <tt>(load "foo.scm")</tt>, paths are relative to the
|
82
|
+
current file
|
83
|
+
|
84
|
+
In addition to the above R5RS features, the following are provided. Heist
|
85
|
+
allows the behaviour of some of these features to be configured on a
|
86
|
+
per-runtime-environment basis.
|
87
|
+
|
88
|
+
* <b>More-helpful-than-usual REPL</b>. Heist's REPL does not clutter
|
89
|
+
your display with prompts and other such cruft. It indents your
|
90
|
+
code automatically, supports tab completion, and output is printed
|
91
|
+
as comments so it's simple to copy code out of a REPL session into
|
92
|
+
a file without modification.
|
93
|
+
* <b>Transparent lazy evaluation (call by need)</b>. Expressions are not
|
94
|
+
evaluated before being passed as arguments, instead they are
|
95
|
+
evaluated as and when the called function requires their values.
|
96
|
+
* <b>Unhygienic macros</b>. Scheme mandates hygienic macros that
|
97
|
+
preserve lexical scoping, but other Lisps use a simpler system that
|
98
|
+
does not impose this restriction. Heist allows hygiene to be
|
99
|
+
disabled, its author not having the requisite experience to decide
|
100
|
+
which system he prefers yet.
|
101
|
+
* <b>Optional continuations</b>. Supporting continuations incurs a
|
102
|
+
constant performance overhead, so if you don't need them you can
|
103
|
+
switch them off.
|
104
|
+
|
105
|
+
|
106
|
+
== Installation and Usage
|
107
|
+
|
108
|
+
sudo gem install hoe
|
109
|
+
sudo gem install heist
|
110
|
+
|
111
|
+
Heist can be run from the command line or embedded in Ruby applications. To
|
112
|
+
run a Scheme file:
|
113
|
+
|
114
|
+
heist path/to/file.scm
|
115
|
+
|
116
|
+
To start an REPL session:
|
117
|
+
|
118
|
+
heist -i
|
119
|
+
|
120
|
+
Both these commands accept a number of runtime configuration options;
|
121
|
+
run <tt>heist -h</tt> for more information.
|
122
|
+
|
123
|
+
To embed Heist in a Ruby application, you need to create an instance of
|
124
|
+
the runtime:
|
125
|
+
|
126
|
+
require 'rubygems'
|
127
|
+
require 'heist'
|
128
|
+
scheme = Heist::Runtime.new(options)
|
129
|
+
|
130
|
+
<tt>options</tt> is an optional argument and is a hash that specifies
|
131
|
+
the behaviour of optional parts of the runtime. For example, to enable
|
132
|
+
lazy evaluation:
|
133
|
+
|
134
|
+
scheme = Heist::Runtime.new(:lazy => true)
|
135
|
+
|
136
|
+
The full list of options is:
|
137
|
+
|
138
|
+
* <tt>:continuations</tt> - sets whether continuations and <tt>(call/cc)</tt>
|
139
|
+
are enabled. Default is <tt>false</tt>.
|
140
|
+
* <tt>:lazy</tt> - sets whether evaluation is lazy. By default this option
|
141
|
+
is <tt>false</tt> and evaluation is eager.
|
142
|
+
* <tt>:unhygienic</tt> - set this to <tt>true</tt> to disable macro hygiene.
|
143
|
+
|
144
|
+
Bear in mind that continuations and lazy evaluation are not currently
|
145
|
+
compatible; enabling continuations forces eager evaluation. Also
|
146
|
+
note that lazy evaluation has a slightly unpredictable effect on the
|
147
|
+
use of macros.
|
148
|
+
|
149
|
+
Every runtime gets its own copy of all the built-in functions. You can add
|
150
|
+
your own functions written in Ruby and Heist will make them available as
|
151
|
+
Scheme procedures. For example, for running tests I do this in my +setup+
|
152
|
+
method:
|
153
|
+
|
154
|
+
@@env = Heist::Runtime.new
|
155
|
+
@@env.define('assert-equal') do |expected, actual|
|
156
|
+
assert_equal(expected, actual)
|
157
|
+
end
|
158
|
+
|
159
|
+
This lets me write, for example, <tt>(assert-equal 7 (+ 3 4))</tt> in my
|
160
|
+
tests. You can place arbitrary Ruby code in your functions, so this is
|
161
|
+
an easy way to expose Ruby functionality to the Scheme environment.
|
162
|
+
|
163
|
+
To run a Scheme file using the runtime, just call:
|
164
|
+
|
165
|
+
scheme.run("path/to/file.scm")
|
166
|
+
|
167
|
+
|
168
|
+
== Notes
|
169
|
+
|
170
|
+
This is alpha-quality software. While every attempt has been made to run
|
171
|
+
valid Scheme code, error handling is at present very weak. Anything
|
172
|
+
explicitly documented in this file can be assumed to work according to
|
173
|
+
the Scheme standard, or according to the information presented here,
|
174
|
+
and can be assumed to be reasonably stable.
|
175
|
+
|
176
|
+
I have not documented how to write your own syntax using Ruby because
|
177
|
+
it requires far too much knowledge of Heist's plumbing at present (I
|
178
|
+
suspect this may be unavoidable). Besides, we have macros so if you
|
179
|
+
want new syntax we've got you covered.
|
180
|
+
|
181
|
+
Heist is extremely liberal as regards symbols. Any sequence of
|
182
|
+
characters that does not contain any spaces or parentheses and that
|
183
|
+
is not a boolean literal, a number or a string is considered a valid
|
184
|
+
symbol. This means that syntax that should be used for chars and
|
185
|
+
vectors will currently parse as symbols.
|
186
|
+
|
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
|
+
Macros are slightly more liberal than R5RS, in that this is a valid
|
195
|
+
macro:
|
196
|
+
|
197
|
+
(define-syntax my-let (syntax-rules ()
|
198
|
+
[(my-let (name value) ... body ...)
|
199
|
+
(let [(name value) ...]
|
200
|
+
body ...)]))
|
201
|
+
|
202
|
+
You are allowed to use ellipses in infix positions, as long as the
|
203
|
+
pattern that follows the ellipsis matches input that the preceeding
|
204
|
+
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:
|
209
|
+
|
210
|
+
(my-let (x 2) (y 3) y)
|
211
|
+
|
212
|
+
Speaking of macros, there is no distinct macro expansion stage in
|
213
|
+
Heist. Macros are expanded as they are encountered at runtime, and
|
214
|
+
their expansions are inlined into the AST to improve performance:
|
215
|
+
the same macro use is never expanded more than once. Macros (and
|
216
|
+
native syntactic forms) are first-class, so they can be easily
|
217
|
+
aliased and used anonymously:
|
218
|
+
|
219
|
+
(define when if)
|
220
|
+
|
221
|
+
((syntax-rules () [(_ expr) expr])
|
222
|
+
(+ 3 4)) ; => 7
|
223
|
+
|
224
|
+
It's not clear whether it would be useful to choose syntactic forms
|
225
|
+
conditionally, certainly this will not work with macros as the
|
226
|
+
inlining process will overwrite conditional code using the first
|
227
|
+
expansion generated.
|
228
|
+
|
229
|
+
Lazy evaluation mode is mainly useful for doing lambda calculus
|
230
|
+
without being concerned about the difference between normal and
|
231
|
+
applicative order, which for example affects the expression for
|
232
|
+
the Y combinator. It displays some interesting properties, such
|
233
|
+
as the fact that this is a perfectly reasonable definition for
|
234
|
+
<tt>Y</tt>:
|
235
|
+
|
236
|
+
(define (Y f)
|
237
|
+
(f (Y f)))
|
238
|
+
; => #<procedure:Y>
|
239
|
+
|
240
|
+
(define fact (Y (lambda (rec)
|
241
|
+
(lambda (x)
|
242
|
+
(if (zero? x)
|
243
|
+
1
|
244
|
+
(* x (rec (- x 1))))))))
|
245
|
+
; => #<procedure:fact>
|
246
|
+
|
247
|
+
(fact 6)
|
248
|
+
; => 720
|
249
|
+
|
250
|
+
|
251
|
+
== License
|
252
|
+
|
253
|
+
(The MIT License)
|
254
|
+
|
255
|
+
Copyright (c) 2009 James Coglan
|
256
|
+
|
257
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
258
|
+
a copy of this software and associated documentation files (the
|
259
|
+
'Software'), to deal in the Software without restriction, including
|
260
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
261
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
262
|
+
permit persons to whom the Software is furnished to do so, subject to
|
263
|
+
the following conditions:
|
264
|
+
|
265
|
+
The above copyright notice and this permission notice shall be
|
266
|
+
included in all copies or substantial portions of the Software.
|
267
|
+
|
268
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
269
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
270
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
271
|
+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
272
|
+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
273
|
+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
274
|
+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Rakefile
ADDED
data/bin/heist
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require File.dirname(__FILE__) + '/../lib/heist'
|
3
|
+
require File.dirname(__FILE__) + '/../lib/bin_spec'
|
4
|
+
|
5
|
+
begin
|
6
|
+
options = Heist::BIN_SPEC.parse
|
7
|
+
rescue Oyster::HelpRendered; exit
|
8
|
+
end
|
9
|
+
|
10
|
+
if options[:interactive] or options[:unclaimed].empty?
|
11
|
+
Heist::REPL.new(options).run
|
12
|
+
else
|
13
|
+
env = Heist::Runtime.new(options)
|
14
|
+
env.run(File.expand_path(options[:unclaimed].first))
|
15
|
+
end
|
16
|
+
|
data/lib/bin_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'oyster'
|
3
|
+
|
4
|
+
Heist::BIN_SPEC = Oyster.spec do
|
5
|
+
name "heist -- Ruby-powered Scheme interpreter, v. #{Heist::VERSION}"
|
6
|
+
author 'James Coglan <jcoglan@googlemail.com>'
|
7
|
+
|
8
|
+
synopsis <<-EOS
|
9
|
+
heist -i [OPTIONS]
|
10
|
+
heist FILE_NAME [OPTIONS]
|
11
|
+
EOS
|
12
|
+
|
13
|
+
flag :interactive, :desc =>
|
14
|
+
'Start an interactive Scheme session'
|
15
|
+
|
16
|
+
flag :lazy, :default => false, :desc =>
|
17
|
+
'Use lazy evaluation order'
|
18
|
+
|
19
|
+
flag :continuations, :default => false, :desc =>
|
20
|
+
'Enable first-class continuations and (call/cc)'
|
21
|
+
|
22
|
+
flag :unhygienic, :default => false, :desc =>
|
23
|
+
'Use Common Lisp-style unhygienic macros'
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,95 @@
|
|
1
|
+
; Any built-in functions that we can implement directly
|
2
|
+
; in Scheme should go here. If at all possible, write
|
3
|
+
; builtins in Scheme rather than Ruby.
|
4
|
+
|
5
|
+
; (not x)
|
6
|
+
; Boolean inverse of x
|
7
|
+
(define (not x)
|
8
|
+
(if x #f #t))
|
9
|
+
|
10
|
+
; Longhand aliases for boolean constants
|
11
|
+
(define true #t)
|
12
|
+
(define false #f)
|
13
|
+
|
14
|
+
; (boolean? x)
|
15
|
+
; Returns true iff x is a boolean value
|
16
|
+
(define (boolean? x)
|
17
|
+
(or (eqv? x #t) (eqv? x #f)))
|
18
|
+
|
19
|
+
; (number? x)
|
20
|
+
; Returns true iff x is any type of number
|
21
|
+
(define number? complex?)
|
22
|
+
|
23
|
+
; (zero? x)
|
24
|
+
; Returns true iff x is zero
|
25
|
+
(define (zero? x)
|
26
|
+
(eqv? x 0))
|
27
|
+
|
28
|
+
; (positive? x)
|
29
|
+
; Returns true iff x > 0
|
30
|
+
(define (positive? x)
|
31
|
+
(> x 0))
|
32
|
+
|
33
|
+
; (negative? x)
|
34
|
+
; Returns true iff x < 0
|
35
|
+
(define (negative? x)
|
36
|
+
(< x 0))
|
37
|
+
|
38
|
+
; (odd? x)
|
39
|
+
; Returns true iff x is odd
|
40
|
+
(define (odd? x)
|
41
|
+
(= 1 (remainder x 2)))
|
42
|
+
|
43
|
+
; (even? x)
|
44
|
+
; Returns true iff x is even
|
45
|
+
(define (even? x)
|
46
|
+
(zero? (remainder x 2)))
|
47
|
+
|
48
|
+
; (abs x)
|
49
|
+
; Returns the absolute value of a number
|
50
|
+
(define (abs x)
|
51
|
+
(if (negative? x)
|
52
|
+
(- x)
|
53
|
+
x))
|
54
|
+
|
55
|
+
; (gcd x y)
|
56
|
+
; Returns the greatest common divisor of two numbers
|
57
|
+
; http://en.wikipedia.org/wiki/Euclidean_algorithm
|
58
|
+
; TODO take >2 arguments
|
59
|
+
(define (gcd x y)
|
60
|
+
(if (zero? y)
|
61
|
+
(abs x)
|
62
|
+
(gcd y (remainder x y))))
|
63
|
+
|
64
|
+
; (lcm x y)
|
65
|
+
; Returns the lowest common multiple of two numbers
|
66
|
+
; http://en.wikipedia.org/wiki/Least_common_multiple
|
67
|
+
; TODO take >2 arguments
|
68
|
+
(define (lcm x y)
|
69
|
+
(/ (abs (* x y))
|
70
|
+
(gcd x y)))
|
71
|
+
|
72
|
+
(define ceiling ceil)
|
73
|
+
|
74
|
+
; (factorial x)
|
75
|
+
; Returns factorial of x
|
76
|
+
(define (factorial x)
|
77
|
+
(define (iter y acc)
|
78
|
+
(if (zero? y)
|
79
|
+
acc
|
80
|
+
(iter (- y 1) (* y acc))))
|
81
|
+
(iter x 1))
|
82
|
+
|
83
|
+
; (newline)
|
84
|
+
; prints a new-line character
|
85
|
+
(define (newline)
|
86
|
+
(display "\n"))
|
87
|
+
|
88
|
+
; (force)
|
89
|
+
; Extracts the value of a promise created using (delay)
|
90
|
+
(define (force promise) (promise))
|
91
|
+
|
92
|
+
; (call/cc)
|
93
|
+
; Alias for (call-with-current-continuation)
|
94
|
+
(define call/cc call-with-current-continuation)
|
95
|
+
|