heist 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,10 @@
1
+ === Version 0.3.1 (2009-08-23)
2
+
3
+ * Added the (rationalize) procedure
4
+ * Allowed (gcd) and (lcm) to take more than two arguments
5
+ * Fixed string output so the REPL prints all data types correctly
6
+
7
+
1
8
  === Version 0.3.0 (2009-07-31)
2
9
 
3
10
  We've got all your data types now
data/README.txt CHANGED
@@ -38,7 +38,7 @@ languages.
38
38
  Heist nominally targets R5RS (http://www.schemers.org/Documents/Standards/R5RS/HTML).
39
39
  It has good support for many Scheme runtime features such as tail call
40
40
  optimisation, macros and first-class continuations, as well as reasonably
41
- complete numeric and list libraries.
41
+ complete libraries for all the Scheme data types.
42
42
 
43
43
  Currently implemented R5RS features include:
44
44
 
@@ -71,9 +71,9 @@ Currently implemented R5RS features include:
71
71
  <tt>abs</tt>, <tt>quotient</tt>, <tt>remainder</tt>, <tt>modulo</tt>,
72
72
  <tt>gcd</tt>, <tt>lcm</tt>, <tt>numerator</tt>, <tt>denominator</tt>,
73
73
  <tt>floor</tt>, <tt>ceiling</tt>, <tt>truncate</tt>, <tt>round</tt>,
74
- <tt>exp</tt>, <tt>log</tt>, <tt>sin</tt>, <tt>cos</tt>, <tt>tan</tt>,
75
- <tt>asin</tt>, <tt>acos</tt>, <tt>atan</tt>, <tt>sqrt</tt>, <tt>expt</tt>,
76
- <tt>make-rectangular</tt>, <tt>make-polar</tt>, <tt>real-part</tt>,
74
+ <tt>rationalize</tt>, <tt>exp</tt>, <tt>log</tt>, <tt>sin</tt>, <tt>cos</tt>,
75
+ <tt>tan</tt>, <tt>asin</tt>, <tt>acos</tt>, <tt>atan</tt>, <tt>sqrt</tt>,
76
+ <tt>expt</tt>, <tt>make-rectangular</tt>, <tt>make-polar</tt>, <tt>real-part</tt>,
77
77
  <tt>imag-part</tt>, <tt>magnitude</tt>, <tt>angle</tt>, <tt>number->string</tt>,
78
78
  <tt>string->number</tt>
79
79
  * Boolean library: <tt>and</tt>, <tt>or</tt>, <tt>not</tt>, <tt>boolean?</tt>
@@ -215,7 +215,9 @@ interface. Quoting syntax is out, so the expression <tt>'(1 2 3)</tt> would
215
215
  need to be written <tt>[:quote, [1, 2, 3]]</tt>. Dotted pairs and improper
216
216
  lists are also not available, though you can work around this to some extent
217
217
  using <tt>:cons</tt>. Vectors should be written as <tt>[:vector, 1, 2, 3]</tt>
218
- for example. Characters are not supported at all.
218
+ for example. Characters can be generated using the <tt>char</tt> procedure
219
+ with a unit-length string, for example <tt>[:char, "Z"]</tt> produces the
220
+ character <tt>#\\Z</tt>.
219
221
 
220
222
 
221
223
  == Notes
@@ -226,6 +228,8 @@ explicitly documented in this file can be assumed to work according to
226
228
  the Scheme standard, or according to the information presented here,
227
229
  and can be assumed to be reasonably stable.
228
230
 
231
+ === Ruby-based syntax
232
+
229
233
  I have not documented how to write your own syntax using Ruby because
230
234
  it requires far too much knowledge of Heist's plumbing at present (I
231
235
  suspect this may be unavoidable). Besides, we have macros so if you
@@ -233,11 +237,25 @@ want new syntax we've got you covered. In fact, writing syntax using
233
237
  macros makes sure that new syntactic forms support continuations
234
238
  correctly, and Heist itself eschews Ruby-based syntax where possible.
235
239
 
240
+ === Valid symbols
241
+
236
242
  Heist is extremely liberal as regards symbols. Any sequence of
237
243
  characters that does not contain any spaces or parentheses and that
238
- is not a boolean literal, a number or a string is considered a valid
239
- symbol. This means that syntax that should be used for chars and
240
- vectors will currently parse as symbols.
244
+ is not a boolean literal, a number, a character literal or a string
245
+ is considered a valid symbol.
246
+
247
+ === Vectors and quoting
248
+
249
+ Vectors do not need to be quoted, for example the expression <tt>#(1 2 3)</tt>
250
+ evaluates to itself. If a vector is quoted, it is made immutable and
251
+ a quoted vector expression returns the same in-memory object every time
252
+ it is evaluated. In contrast, an unquoted vector returns a new vector
253
+ object every time it is evaluated. Unquoted vectors are not frozen
254
+ as this makes macro transformations hard to implement, and because we
255
+ cannot let the <tt>vector-set!</tt> procedure modify the parse tree
256
+ each unquoted vector is copied on evaluation.
257
+
258
+ === Macros
241
259
 
242
260
  Macros are slightly more liberal than R5RS, in that this is a valid
243
261
  macro:
@@ -274,6 +292,8 @@ conditionally, certainly this will not work with macros as the
274
292
  inlining process will overwrite conditional code using the first
275
293
  expansion generated.
276
294
 
295
+ === Laziness
296
+
277
297
  Lazy evaluation mode is mainly useful for doing lambda calculus
278
298
  without being concerned about the difference between normal and
279
299
  applicative order, which for example affects the expression for
@@ -2,6 +2,7 @@
2
2
  ; in Scheme should go here. If at all possible, write
3
3
  ; builtins in Scheme rather than Ruby.
4
4
 
5
+ (define quit exit)
5
6
 
6
7
  ; (newline)
7
8
  ; prints a new-line character
@@ -149,22 +150,48 @@
149
150
  ; (gcd x y)
150
151
  ; Returns the greatest common divisor of two numbers
151
152
  ; http://en.wikipedia.org/wiki/Euclidean_algorithm
152
- ; TODO take >2 arguments
153
- (define (gcd x y)
154
- (if (zero? y)
155
- (abs x)
156
- (gcd y (remainder x y))))
153
+ (define (gcd x y . rest)
154
+ (if (null? rest)
155
+ (if (zero? y)
156
+ (abs x)
157
+ (gcd y (remainder x y)))
158
+ (apply gcd (cons (gcd x y) rest))))
157
159
 
158
160
  ; (lcm x y)
159
161
  ; Returns the lowest common multiple of two numbers
160
162
  ; http://en.wikipedia.org/wiki/Least_common_multiple
161
- ; TODO take >2 arguments
162
- (define (lcm x y)
163
- (/ (abs (* x y))
164
- (gcd x y)))
163
+ (define (lcm x y . rest)
164
+ (if (null? rest)
165
+ (/ (abs (* x y))
166
+ (gcd x y))
167
+ (apply lcm (cons (lcm x y) rest))))
165
168
 
166
169
  (define ceiling ceil)
167
170
 
171
+ ; (rationalize x tolerance)
172
+ ; Returns the simplest rational number that differs from x by
173
+ ; no more than tolerance. Here 'simplest' means the smallest
174
+ ; possible denominator is found first, and with that set the
175
+ ; smallest corresponding numerator is chosen.
176
+ (define (rationalize x tolerance)
177
+ (cond [(rational? x)
178
+ x]
179
+ [(not (zero? (imag-part x)))
180
+ (make-rectangular (rationalize (real-part x) tolerance)
181
+ (rationalize (imag-part x) tolerance))]
182
+ [else
183
+ (let* ([t (abs tolerance)]
184
+ [a (- x t)]
185
+ [b (+ x t)])
186
+ (do ([i 1 (+ i 1)]
187
+ [z #f])
188
+ ((number? z) z)
189
+ (let ([p (ceiling (* a i))]
190
+ [q (floor (* b i))])
191
+ (if (<= p q)
192
+ (set! z (/ (if (positive? p) p q)
193
+ i))))))]))
194
+
168
195
  ; (make-polar magnitude angle)
169
196
  ; Returns a new complex number with the given
170
197
  ; magnitude and angle
@@ -342,6 +369,15 @@
342
369
 
343
370
  ; Character functions
344
371
 
372
+ ; (char string)
373
+ ; Returns a character from a single-character string. Mostly
374
+ ; useful for succinct representation of characters in hand-
375
+ ; written Ruby code.
376
+ (define (char string)
377
+ (if (and (string? string) (= (string-length string) 1))
378
+ (string-ref string 0)
379
+ '()))
380
+
345
381
  ; (char-upper-case? letter)
346
382
  ; Returns true iff letter is an uppercase letter
347
383
  (define (char-upper-case? letter)
@@ -9,7 +9,7 @@ require 'treetop'
9
9
  # utility methods that don't belong anywhere else. See the README for an
10
10
  # overview of Heist's features.
11
11
  module Heist
12
- VERSION = '0.3.0'
12
+ VERSION = '0.3.1'
13
13
 
14
14
  ROOT_PATH = File.expand_path(File.dirname(__FILE__))
15
15
  PARSER_PATH = ROOT_PATH + '/parser/'
@@ -66,6 +66,18 @@ module Heist
66
66
  op1.to_f / op2
67
67
  end
68
68
 
69
+ # Returns a string representation of the object suitable for display on the
70
+ # command line. Some built-in Ruby types need special handling to display
71
+ # according to Scheme conventions.
72
+ def stringify(object)
73
+ case object
74
+ when Runtime::Character, String then object.inspect
75
+ when TrueClass then '#t'
76
+ when FalseClass then '#f'
77
+ else object.to_s
78
+ end
79
+ end
80
+
69
81
  end
70
82
  end
71
83
 
@@ -31,7 +31,7 @@ module Heist
31
31
  reset!
32
32
  result = @scope.eval(tree)
33
33
  unless result.nil?
34
- puts "; => #{ text(result) }\n\n"
34
+ puts "; => #{ Heist.stringify(result) }\n\n"
35
35
  @results << result
36
36
  @scope['^'] = result
37
37
  end
@@ -64,15 +64,6 @@ module Heist
64
64
  @indent = 0
65
65
  end
66
66
 
67
- def text(object)
68
- case object
69
- when Runtime::Character, String then object.inspect
70
- when TrueClass then '#t'
71
- when FalseClass then '#f'
72
- else object.to_s
73
- end
74
- end
75
-
76
67
  def push(line)
77
68
  old_depth = depth
78
69
  @buffer << line
@@ -218,13 +218,13 @@ module Heist
218
218
  end
219
219
 
220
220
  # Returns a Scheme-style string representation of the list.
221
- def inspect
221
+ def to_s
222
222
  strings = []
223
- tail = each { |value| strings << value.inspect }.cdr
223
+ tail = each { |value| strings << Heist.stringify(value) }.cdr
224
224
  '(' + (strings * ' ') +
225
225
  (tail == NULL ? '' : ' . ' + tail.to_s) + ')'
226
226
  end
227
- alias :to_s :inspect
227
+ alias :inspect :to_s
228
228
  end
229
229
 
230
230
  end
@@ -54,10 +54,10 @@ module Heist
54
54
  end
55
55
 
56
56
  # Returns a Scheme-style string representation of the +Vector+.
57
- def inspect
58
- '#(' + map { |cell| cell.inspect }.join(' ') + ')'
57
+ def to_s
58
+ '#(' + map { |cell| Heist.stringify(cell) }.join(' ') + ')'
59
59
  end
60
- alias :to_s :inspect
60
+ alias :inspect :to_s
61
61
  end
62
62
 
63
63
  end
@@ -41,6 +41,8 @@
41
41
  (assert-equal 4 (gcd 32 -36))
42
42
  (assert-equal 288 (lcm 32 -36))
43
43
  (assert-equal 288.0 (lcm 32.0 -36)) ; inexact
44
+ (assert-equal 6 (lcm 2 6))
45
+ (assert-equal 12 (lcm 2 6 4))
44
46
 
45
47
  (assert-equal 3 (numerator (/ 6 4)))
46
48
  (assert-equal 2 (denominator (/ 6 4)))
@@ -39,3 +39,10 @@
39
39
 
40
40
  (assert-equal 1 (make-polar 1 0))
41
41
 
42
+ (assert-equal 3 (rationalize 5.5 3))
43
+ (assert-equal 4 (rationalize 5.5 2))
44
+ (assert-equal 5 (rationalize 5.5 1))
45
+ (assert-equal 11/2 (rationalize 5.5 0.1))
46
+ (assert-equal 16/3 (rationalize 5.25 0.1))
47
+ (assert-equal 21/4 (rationalize 5.25 0.01))
48
+
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: heist
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - James Coglan
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-31 00:00:00 +01:00
12
+ date: 2009-08-23 00:00:00 +01:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency