heist 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
|