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!")