Subject: Re: Lisp Application Server
From: rpw3@rpw3.org (Rob Warnock)
Date: Fri, 11 Jul 2008 21:04:19 -0500
Newsgroups: comp.lang.lisp
Message-ID: <XsmdncUTM76-jOXVnZ2dnUVZ_sHinZ2d@speakeasy.net>
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