I'm a very satisfied Gambit user, as my program became fast enough to
refute some C calculations my advisor made 20 years ago. My advisor
was clever enough to prove his answers were wrong, even though his
program no longer runs. Thanks to Marc for offering to help optimize
my code: that got me to look at my code myself and make an obvious
optimization. Guillaume's profiler certainly helped locate a hotspot.
But I think Gambit is a lot better than the manual would indicate to a
non-expert schemer like me. I have 4 "advertising" tips:
************ blinding speed ************
The first node does some great advertising:
With appropriate declarations in the source code the executable
programs generated by the compiler run roughly as fast as
equivalent C programs.
I believe this now, with my program's speed. But it would be even
better if you cross-ref'ed the node "Miscellaneous extensions", where
`declarations' is explained, and if that node included Guillaume's
advice to me: stick something like this at the top of your program:
(declare
(standard-bindings)
(fixnum)
(not safe)
(inline)
(inlining-limit 1000)
(block))
One thing great about "fast as equivalent C programs" is it's the
first thing a reader will see! If you bury great stuff deep in the
manual, then maybe you'll restrict your users to expert programmers.
The manual looks very accurate to me, but it's very technical.
************ great debugger ************
I've often felt that bad or nonexistent debuggers is the Achilles heel
of Scheme. But it looks to me like Gambit has a great debugger! I
think the first node "The Gambit-C system" shoul say something like:
`Gambit has a good debugger. See the examples in the nodes "Debugging
commands" and "Procedures related to debugging" for examining
variables in case of an error, and breakpoints and single-stepping.'
************ Case sensitive ************
The node "Runtime options for all programs" says that Gambit is
case-sensitive by default. I think that's a huge plus, and should be
mentioned in the 1st node. I think all mathematically-inclined folks
will agree with me, as one typically writes, "Let X be a set, and let
x be an element of X", which turns naturally into Scheme
(let ([x (car X)]) ...)
I think you should target folks who use DrScheme, written by your R6RS
co-Editor Matthew Flatt. DrScheme is really slow, but it has some
real pedagogical advantages, I think, including case-sensitivity. I
would've used Gambit years ago if I'd known it was case-sensitive.
************ read-all: don't compile data ************
I finally understood some advice Guillaume posted: don't load/include
big data files: it slows down gsc/gcc unbearably. You don't need to
load/include, because of Gambit extensions like read-all. This helps
with my Curtis-algorithm program, but it was crucial for an example
program, where I gave an independent refutation of an error my advisor
made in t = 71, where I differentiated a polynomial with 75,000+ terms
of length 10! In 16.6 minutes! Look at this short program:
(declare
(standard-bindings)
(fixnum)
(not safe)
(inline)
(inlining-limit 1000)
(block))
(include "adem.scm")
(define inport (open-input-file "tag-data-t-71"))
(define X (read-all inport))
(close-input-port inport)
(pretty-print (length X))
(pretty-print (Poly-first X))
(time (pretty-print (Poly-first (D X))))
75299
(4 8 4 5 3 5 9 3 5 7 7)
(3 4 4 2 3 5 3 5 9 7 7 7)
(time (pretty-print (Poly-first (D X))))
998093 ms real time, 16.6 minutes
997940 ms cpu time (997840 user, 100 system)
3204 collections accounting for 365525 ms real time (365690 user, 30 system)
112648202368 bytes allocated
13318 minor faults
3 major faults
BTW can someone explain this figure, 112648202368 bytes allocated?
Did I really use 112.6 gB? My machine "only" has 1 gB of memory.
An important extension to Scheme like `read-all' maybe should be more
prominently mentioned, and it's usefulness stressed. The description
is fine, but I didn't find these examples very illuminating:
- procedure: read-all [PORT [READER]]
This procedure repeatedly calls the procedure READER with PORT as
the sole argument and accumulates a list of each value returned up
to the end-of-file object. The procedure `read-all' returns the
accumulated list without the end-of-file object. If it is not
specified, PORT defaults to the current input-port. If it is not
specified, READER defaults to the procedure `read'.
For example:
> (call-with-input-string "3,2,1\ngo!" read-all)
(3 ,2 ,1 go!)
> (call-with-input-string "3,2,1\ngo!"
(lambda (p) (read-all p read-char)))
(#\3 #\, #\2 #\, #\1 #\newline #\g #\o #\!)
> (call-with-input-string "3,2,1\ngo!"
(lambda (p) (read-all p read-line)))
("3,2,1" "go!")