Rainer Joswig <joswig@lisp.de> wrote:
+---------------
| rpw3@rpw3.org (Rob Warnock) wrote:
| > $ cat test_cmucl # [Note 1]
| > #!/usr/local/bin/cmucl -script
| > (format t "Hello, world!~%")
| > $ /usr/bin/time ./test_cmucl
| > Hello, world!
| > 0.01 real 0.00 user 0.00 sys
| > $
...
| > [1] This uses my "-script" add-on to CMUCL to support "#!" scripts:
| > http://rpw3.org/hacks/lisp/site-switch-script.lisp
|
| Rob, it would be cool if you could collect all those nifty
| tricks^h^h^h^h^hmagic and publish something about it sometime.
+---------------
To some extent, I've already started, see <http://rpw3.org/hacks/lisp/>,
and *am* [albeit way too slowly, sorry!] planning on cleaning up and
more fully populating my nearly-empty website. [Soon, soon!]
The main "trick"[1] for convenient CMUCL "scripting" is the
"site-switch-script" hack.[2] Most everything else is just the sort
of "one-liner" personalizations any programmer carries around from
O/S to O/S and language to language over the years, and little things
like a "peek-poke" library that just gives to low-level access to
machine-code "load" & "store" and O/S "mmap()". *That* one I've
moved from C to Tcl to Scheme and, most recently, to CL (CMUCL),
always in support of user-mode hardware development/debugging.
[I can publish the CMUCL variant, if anyone cares.]
The only other generally-useful trick for CL scripting that I can
think of at the moment is to make your "main" function use keywords,
and then call it in the script this way [or, mutatis mutandis, however
your CL scripting command-line args]:
#!/usr/local/bin/cmucl -script
...[DEFUN/REQUIRE/LOAD/ASDF whatever you need]...
(defun main (&key ...whatever [incl. defaults]...)
...)
(unless *script-exit-hooks* ; Debugging?
(apply 'main (mapcar #'read-from-string *script-args*)))
This gives you a dirt-simple "getopt()"-euivalent for free!
E.g., I used this in a script which calculates R-C time constants:
$ time-constant :r 10e3 :c 4.7e-6 :v0 0 :vcc 5 :v 3
0.043065663 s to reach 3 V
$ time-constant :r 10e3 :c 4.7e-6 :v0 0 :vcc 5 :time 40e-3
2.8651977 V after 0.04 s
$ time-constant :rc .047 :v0 0 :vcc 5 :time 40e-3
2.8651977 V after 0.04 s
$ time-constant :v0 0 :vcc 5 :time 40e-3
0.19605255 V after 0.04 s
$
Note that :RC defaults to (* R C), and :R & :C are defaulted to 1
[so :RC defaults to 1 if neither :R nor :C are specified], but the
others aren't. Whether you're asking for "time until voltage" or
"voltage after time" is determined by which of :V or :TIME are given.
The rest of those 47 or so CMUCL scripts were just more of the same
little personal tools, the sort that everybody writes [don't they?!?]
in *some* scripting language. I just happen to prefer CL these days
for that, when it's reasonable. Note: I'm not fanatic; I use other
scripting languages, and don't re-code things just to change language.
Here's a rough breakdown of things in my current "~/bin/" directory
["file ~/bin/* | grep executable | sort | uniq -c | sort -rn" then edit]:
130 Bourne shell script text executable
45 /usr/local/bin/cmucl -script script text executable
22 /usr/local/bin/mzscheme -r script text executable
12 ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD)
7 perl script text executable
5 /usr/local/bin/clisp script text executable
3 /usr/local/bin/elk -l script text executable
3 FreeBSD/i386 compact demand paged dynamically linked executable (*OLD!*)
2 new awk script text executable
2 C shell script text executable
1 tcl -f script text executable
1 zsh script text executable
1 ELF 64-bit LSB executable, AMD x86-64, version 1 (FreeBSD)
Most of those 130 Bourne shell scripts are old, really, *really* old!! ;-}
Many date back to the mid-1980s and early 1990s. And the MzScheme
scripts are all from the '90s [since I switched to CL circa 2000].
My one larger work that I've intended to publish for some time but
haven't yet is my "appsrv" web application server infrastructure,
see <http://rpw3.org/hacks/lisp/appsrv-demo.lhp>, which I haven't
rushed because: (1) there are unfortunately a few remnants of the
somewhat proprietary application it was initially written to support
that haven't been sanitized yet; (2) even though "appsrv" was written
in 2002, well before many of the others at <http://www.cliki.net/web>,
because of point #1 it's been left in the dust, as it were, by the
progress of others [cl-modlisp, Hunchentoot, cl-weblocks, etc.];
(3) it wasn't all that featureful in the first place -- "just another
mod_lisp-using app" [though it didn't use "mod_lisp" per se, see
<http://rpw3.org/hacks/lisp/cgi_sock.c>]; and, finally, (4) it was
my very first largish, "production" Common Lisp application [though
I had been using Scheme for a decade], so in retrospect the code
really stinks in places. [Though it's been *very* solid, no serious
bugs in the infrastructure code in the last 5 years!]
+---------------
| I guess a little tutorial of yours at some Lisp event would
| also be very educational. I always enjoy reading your posts!
+---------------
Well, thanks! (*blush*)
I do plan on being at ILC 2009, but I'm somewhat doubtful a whole
"tutorial" could be built out of my little hodgepodge of personal
hacks [though if I'm wrong, feel free to try to convince me], which
are mostly quite CMUCL-specific in any case. Maybe what would work
better is some sort of multi-presenter "hacks" poster session,
where a half-dozen people -- hopefully at least one for every major
CL implementation -- scrawl a bunch of flip-chart sheets with one
hack per sheet and then post them up on the wall next to them.
That is, a mini-"exhibit hall" of hacks, with one "booth" [part of
a wall] per CL implementation and (at least) one person standing there
to explain/discuss/argue the hacks related to that implementation.
We'd also need several flip-charts for people to write/post new hacks
during the session, and the presenter(s) would have to promise to
write up such improve hacks for later posting on the ALU website
[since they'd be too late for the proceedings]. Does that sound
worthwhile?
-Rob
[1] No, you were right, my CMUCL "#!" hack *is* "deep magic". ;-}
But I tried very hard to allow it to be used *without*
anyone having to grok the magic, in most cases.
See <http://rpw3.org/hacks/lisp/site-switch-script.lisp>
for the gory, ugly, grotesque details, if you must! ;-} ;-}
Writing that involved wading around in the sewer that is
the CMUCL function SAVE-LISP (in "src/code/save.lisp") and
figuring out how to subvert the normal command line parsing
code: (1) to allow command line options of "#!" scripts to be
passed to the script code; (2) to suppress CMUCL's built-in
command line parser from seeing them; and (3) to pervert CMUCL's
built-in command line handling to get around the re-binding of
many specials that's done during the LOAD of the "site-init" code
[which in turn loads "site-switch-script"] and to provide a hook
for running user code in the normal *outer* binding context after
the LOAD of the user script finishes [see all the *SCRIPT-EXIT-HOOKS*
stuff near the end of "site-switch-script"].
I'm not sure that anyone but me will ever use it this way
[though *I* use it this way a lot!], but if you want your
script to set up a bunch of stuff and then drop into a normal
REPL, do this:
#!/usr/local/bin/cmucl -script
...[DEFUN/REQUIRE/LOAD/ASDF whatever you need]...
(setf *prompt* #|<|# "my-custom-prompt> ") ; [Optional]
(push :repl *script-exit-hooks*) ; Drop into normal REPL
[2] Yes, I've been talking to Carl Shapiro about whether or how to
get the "#!" hack [or equiv.] into the standard CMUCL distribution.
As you can see from the code, there's *lots* of room for conflicting
opinions over what "doing it right" might mean. ;-}
-----
Rob Warnock <rpw3@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607