Subject: Re: Dynamic unquote ( , )?
From: rpw3@rpw3.org (Rob Warnock)
Date: Thu, 09 Feb 2006 23:26:24 -0600
Newsgroups: comp.lang.lisp
Message-ID: <7eCdnbDjnLKduXHeRVn-iA@speakeasy.net>
Alexander Schmolck  <a.schmolck@gmail.com> wrote:
+---------------
| rpw3@rpw3.org (Rob Warnock) writes:
| > This is why I said it's "practically impossible to write a CL Shell
| > with Scsh-style syntax" [unless you manually add explicit backquotes
| > at various points].
| 
| I haven't really thought much about it or tested it, but why doesn't
| this simple approach below work for that purpose...
+---------------

Yeah, it sort of works, for simple cases, though I haven't tested
the corner cases [since I don't have a QUASIQUOTE expander yet to
test it with (see below)]:

    > (defun run-func (form)
	(format t "RUN-FUNC saw this form: ~s~%" form))

    RUN-FUNC
    > (defmacro run (run-form)
	(list 'run-func (list 'quote run-form)))

    RUN
    > (run (ls -l foo))
    RUN-FUNC saw this form: (LS -L FOO)
    NIL
    > 

Note that for a real "CLsh", you'd probably want to run with
readtable-case :INVERT to avoid upcasing the Unix commands.  ;-}  ;-}

Unfortunately, having usurped backquote/comma/comma-at from READ,
one is now stuck needing to do one's own full backquote expansion,
which includes all the gore of handling lexical environments as well.
That is, you get this:

    > (let ((file "some.file")
	    (flags '(-lm -lbsd)))
	(run (cc ,file ,@flags)))
    ; In: LET ((FILE "some.file") (FLAGS '#))
    ;   (LET (# #)
    ;     (RUN #))
    ; Note: Variable FILE defined but never used.
    ; 
    ; Note: Variable FLAGS defined but never used.
    RUN-FUNC saw this form: (CC (UNQUOTE FILE) (UNQUOTE-SPLICING FLAGS))
    NIL
    > 

when you really wanted this:  ;-}  ;-}

    RUN-FUNC saw this form: (CC "some.file" -LM -LBSD)

And worse than that, even. Notice that RUN-FUNC got the variable
*names*, not their values, and that the bindings are *lexical*,
not global, so RUN-FUNC isn't going to be able to figure out what
to replace FILE & FLAGS with. We're going to have to extend the
whole infrastructure with something like this:

    > (defun run-func (form env)
	(format t "RUN-FUNC saw this form: ~s~%In this env: ~s~%" form env))

    RUN-FUNC
    > (defmacro run (run-form &environment env)
	(list 'run-func (list 'quote run-form) (list 'quote env)))

    RUN
    > (run (ls -l foo))
    RUN-FUNC saw this form: (LS -L FOO)
    In this env: NIL
    NIL
    > (let ((file "some.file")
	    (flags '(-lm -lbsd)))
	(run (cc ,file ,@flags)))
    ; In: LET ((FILE "some.file") (FLAGS '#))

    ;   (LET (# #)
    ;     (RUN #))
    ; Note: Variable FILE defined but never used.
    ; 
    ; Note: Variable FLAGS defined but never used.
    RUN-FUNC saw this form: (CC (UNQUOTE FILE) (UNQUOTE-SPLICING FLAGS))
    In this env: #S(C::LEXENV
		      :FUNCTIONS NIL
		      :VARIABLES ((FLAGS
				   . #<C::LAMBDA-VAR #x58930165  NAME= FLAGS>)
				  (FILE . #<C::LAMBDA-VAR #x5893010D  NAME= FILE>))
		      :BLOCKS NIL
		      :TAGS NIL
		      :TYPE-RESTRICTIONS NIL
		      :LAMBDA #<LAMBDA #x5893021D
				  NAME= NIL
				  TYPE= #<KERNEL::BUILT-IN-CLASS
					  FUNCTION (read-only) {280576F5}>
				  WHERE-FROM= :DEFINED
				  VARS= (FILE FLAGS)>
		      :CLEANUP NIL
		      :COOKIE #S(C::COOKIE
				   :SPEED 1
				   :SPACE 1
				   :SAFETY 1
				   :CSPEED 1
				   :BREVITY 1
				   :DEBUG 2)
		      :INTERFACE-COOKIE #S(C::COOKIE
					     :SPEED NIL
					     :SPACE NIL
					     :SAFETY NIL
					     :CSPEED NIL
					     :BREVITY NIL
					     :DEBUG NIL)
		      :OPTIONS NIL
		      :DYNAMIC-EXTENT NIL)
    NIL
    > 

Ooooh! Look at that loverly idiosyncratic environment! How is my
QUASIQUOTE macro expander going to extract the values of FILE & FLAGS
from *that* in a portable way??!?!?

[Cue Duane Rettig, waiting in the wings for an encore presentation
of his Environments Access module...  ;-}  ;-}  ]

Anyway, like I said before (too many posts ago), doing a "CLsh" that
used "pure" Scsh syntax would be quite hard. It might be better to
just give up on trying to achieve the "pure" syntax and accept that
we would type the extra backquote character in all of the run-process
convenience forms. Then it "just works", right out of the box:

    > (defun run (form)
	(format t "RUN saw this form: ~s~%" form))
    > (let ((file "some.file")
	    (flags '(-lm -lbsd)))
	(run `(cc ,file ,@flags)))
    RUN saw this form: (CC "some.file" -LM -LBSD)
    NIL
    > 

+---------------
| (you don't need backquote to accept additional commas, right?)?
+---------------

What do you mean by "additional commas"? Nesting? Of course!
It needs to work *just* like normal CL backquote, otherwise
your "shell" syntax won't be "CL".


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607