From: Kaz Kylheku
Subject: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <cf333042.0303081825.278f7d56@posting.google.com>
Can someone make comments on the portability of this?

;;;
;;; Hack to discover how the Lisp implementation represents
;;; the unquote operators, and to use that representation
;;; as a template to generate unquotes.
;;;

(defun replace-tree (tree old new)
  (cond
    ((eq tree old)
       new)
    ((atom tree)
       tree)
    (t (cons (replace-tree (first tree) old new)
	     (replace-tree (rest tree) old new)))))

(let* ((sym (gensym))
       (uq-form (second ``,,sym))
       (uqs-form (first (second ``(,@,sym)))))

  (defun unquote (arg)
    (replace-tree uq-form sym arg))
  
  (defun unquote-splicing (arg)
    (replace-tree uqs-form sym arg)))



Example use with results from CLISP.

(unquote 'a) 

  ==> (SYSTEM::UNQUOTE A)

(unquote-splicing 3) 

  ==> (SYSTEM::SPLICE (SYSTEM::UNQUOTE 3))

``,',(mapcar #'unquote-splicing '(a b c d)) 

  ==>  `(,@A ,@B ,@C ,@D)

``,',(mapcar #'unquote '(a b c d))

  ==>  `(,A ,B ,C ,D)


``,',(unquote-splicing 3)

  ==> `,@3   ;; impossible notation, but generated nicely by
             ;; this implementation's formatter. :)


This kind of thing would be helpful for instance in macros that write
macros. Say you have to write a macro whose expansion contains
macrolets, but you need a variable number of unquotes in the macrolet
body templates based on how the overall macro is invoked.

From: Alexey Dejneka
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <m3bs0l9qin.fsf@comail.ru>
Hello,

···@ashi.footprints.net (Kaz Kylheku) writes:

> Can someone make comments on the portability of this?
> 
> ;;;
> ;;; Hack to discover how the Lisp implementation represents
> ;;; the unquote operators, and to use that representation
> ;;; as a template to generate unquotes.
> ;;;
[...]
> (let* ((sym (gensym))
>        (uq-form (second ``,,sym))
>        (uqs-form (first (second ``(,@,sym)))))

It does not work in SBCL:

* (write '`(a ,@b c) :readably t :pretty nil)
(SB-IMPL::BACKQ-CONS (QUOTE A) (SB-IMPL::BACKQ-APPEND B (QUOTE (C))))
`(A ,@B C)
* (write '``,,a :readably t :pretty nil)
A
A

-- 
Regards,
Alexey Dejneka

"<Zhivago> mutants tend to turn evil after a while, and go around
eating people's brains." -- #lisp
From: Kaz Kylheku
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <cf333042.0303091235.3f951033@posting.google.com>
Alexey Dejneka <········@comail.ru> wrote in message news:<··············@comail.ru>...
> Hello,
> 
> ···@ashi.footprints.net (Kaz Kylheku) writes:
> 
> > Can someone make comments on the portability of this?
> > 
> > ;;;
> > ;;; Hack to discover how the Lisp implementation represents
> > ;;; the unquote operators, and to use that representation
> > ;;; as a template to generate unquotes.
> > ;;;
>  [...]
> > (let* ((sym (gensym))
> >        (uq-form (second ``,,sym))
> >        (uqs-form (first (second ``(,@,sym)))))
> 
> It does not work in SBCL:
> 
> * (write '`(a ,@b c) :readably t :pretty nil)
> (SB-IMPL::BACKQ-CONS (QUOTE A) (SB-IMPL::BACKQ-APPEND B (QUOTE (C))))

I see; the rest of the form is subordinate to the splicing unquote.
What if we simply drop support for splicing unquotes and care about
non-splicing unquote only? They are not all that useful; I don't think
it's as useful to be able to generate a variable-length row of ,@
expressions in a meta-macro; you can probably turn them into a single
,@ and make alternate arrangements for the appending.
From: Pekka P. Pirinen
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <u65qo784z.fsf@globalgraphics.com>
···@ashi.footprints.net (Kaz Kylheku) writes:
> Alexey Dejneka <········@comail.ru> wrote in message news:<··············@comail.ru>...
> > It does not work in SBCL:
> > 
> > * (write '`(a ,@b c) :readably t :pretty nil)
> > (SB-IMPL::BACKQ-CONS (QUOTE A) (SB-IMPL::BACKQ-APPEND B (QUOTE (C))))
> 
> I see; the rest of the form is subordinate to the splicing unquote.
> What if we simply drop support for splicing unquotes and care about
> non-splicing unquote only?

No, that won't fly, either.  As you saw '``,,A -> A in SBCL, and I bet 
  '`(0 ,A) -> (SB-IMPL::BACKQ-LIST 0 A)
At least LW is like that (modulo naming).  These implementations just
don't work on the unquote approach.  Looks similar to Steele's example
implementation from CLtL2, appendix C.

Why don't you give us an example of a macro problem where you need
this, and we could try to find a different solution?
-- 
Pekka P. Pirinen
    I have yet to see any problem, however complicated, which,
when you looked at it in the right way, did not become still
more complicated.	- Poul Anderson
From: Joerg Hoehle
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <ur89btfyj.fsf@dont.t-systems.UCE.spam.no.com>
···············@globalgraphics.com (Pekka P. Pirinen) writes:
> Why don't you give us an example of a macro problem where you need
> this, and we could try to find a different solution?

Here's something where I wish a function/macro could know the format
of backquotes:

CLISP has a FFI:WITH-FOREIGN-OBJECT macro (like LW):
(with-foreign-object (buf '(c-array uint8 32) vector)
  ...body...)

In the macroexpansion, it's trivial to recognize the (QUOTE ...) form
for the foreign type and generate compile-time (or load-time) code for
it, instead of run-time function calls. E.g. it's better for
the resulting (ffi::parse-c-type #) not to get called at run-time.

Now, there's a repeating backquote pattern which goes like this:
(defun foo (seq)
  (with-foreign-object (buf `(c-array uint8 ,(length seq)) seq)
    ...body...))

I wish to optimize this case as well. This (c-array X ,Y) pattern is
supposed to occur often in FFI interaction. I don't want to take
advantage of the fact that it's CLISP's FFI and write unportable code
for CLISP's backquote mechanism only.

Thanks for your help,
	Jorg Hohle
Telekom/T-Systems Technology Center
From: Rob Warnock
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <V0ednadRkco3dO-jXTWc-w@speakeasy.net>
Joerg Hoehle  <············@dont.t-systems.UCE.spam.no.com> wrote:
+---------------
| Now, there's a repeating backquote pattern which goes like this:
| (defun foo (seq)
|   (with-foreign-object (buf `(c-array uint8 ,(length seq)) seq)
|     ...body...))
| 
| I wish to optimize this case as well. This (c-array X ,Y) pattern is
| supposed to occur often in FFI interaction. I don't want to take
| advantage of the fact that it's CLISP's FFI and write unportable code
| for CLISP's backquote mechanism only.
+---------------

That one looks simple. The 2nd arg of the macro is evaluated, right?
[Otherwise backquote wouldn't work in the first place.] So just
hand-expand it:

  (defun foo (seq)
    (with-foreign-object (buf (list 'c-array 'uint8 (length seq)) seq)
      ...body...))

Now it's portable.


-Rob

-----
Rob Warnock, PP-ASEL-IA		<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Kaz Kylheku
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <cf333042.0303170050.1c37a53@posting.google.com>
····@rpw3.org (Rob Warnock) wrote in message news:<······················@speakeasy.net>...
> Joerg Hoehle  <············@dont.t-systems.UCE.spam.no.com> wrote:
> +---------------
> | Now, there's a repeating backquote pattern which goes like this:
> | (defun foo (seq)
> |   (with-foreign-object (buf `(c-array uint8 ,(length seq)) seq)
> |     ...body...))
> | 
> | I wish to optimize this case as well. This (c-array X ,Y) pattern is
> | supposed to occur often in FFI interaction. I don't want to take
> | advantage of the fact that it's CLISP's FFI and write unportable code
> | for CLISP's backquote mechanism only.
> +---------------
> 
> That one looks simple. The 2nd arg of the macro is evaluated, right?

That can't be; (c-array ...) is an expression that specifies an FFI
type. It's not a function or operator.

> [Otherwise backquote wouldn't work in the first place.]

It would work despite that, if the macro recognizes that it has a
backquote form, and then expands it, as a special case:

 (defmacro with-foreign-object ((buffer type seq) &body body
&environment env)
   ;; if type is specified by a backquote expression, expand it.
   (when (backquote-form-p type)
     (setf arg (macroexpand arg env)))
    ...)

That's the kind of thing you could do portably if the notation had a
well-defined target macro language.
From: Jeremy Yallop
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <slrnb6oni5.jsb.jeremy@saturn.cps.co.uk>
Kaz Kylheku wrote:
> (defun replace-tree (tree old new)
>   (cond
>     ((eq tree old)
>        new)
>     ((atom tree)
>        tree)
>     (t (cons (replace-tree (first tree) old new)
> 	     (replace-tree (rest tree) old new)))))

SUBST saves the need to invent this particular wheel.

Jeremy.
From: Kaz Kylheku
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <cf333042.0303100929.1e37aa8e@posting.google.com>
Jeremy Yallop <······@jdyallop.freeserve.co.uk> wrote in message news:<·····················@saturn.cps.co.uk>...
> Kaz Kylheku wrote:
> > (defun replace-tree (tree old new)
> >   (cond
> >     ((eq tree old)
> >        new)
> >     ((atom tree)
> >        tree)
> >     (t (cons (replace-tree (first tree) old new)
> > 	     (replace-tree (rest tree) old new)))))
> 
> SUBST saves the need to invent this particular wheel.
> 
> Jeremy.

Doh! Apologies for the stupidity.
From: Kimmo T Takkunen
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <slrnb6pp0k.b1.ktakkune@sirppi.helsinki.fi>
In article <····························@posting.google.com>, Kaz Kylheku wrote:
> Jeremy Yallop <······@jdyallop.freeserve.co.uk> wrote in message news:<·····················@saturn.cps.co.uk>...
>> Kaz Kylheku wrote:
>> > (defun replace-tree (tree old new)
>> >   (cond
>> >     ((eq tree old)
>> >        new)
>> >     ((atom tree)
>> >        tree)
>> >     (t (cons (replace-tree (first tree) old new)
>> > 	     (replace-tree (rest tree) old new)))))
>> 
>> SUBST saves the need to invent this particular wheel.
>> 
>> Jeremy.
> 
> Doh! Apologies for the stupidity.

Nice to see that I'm not the only one who reinvents functions in CL. 

The feeling you get when you discover that the function you
have just tested and added into your private library of essential
utilities is already in CL should have its own name IMHO.

 Kimmo
-- 
((lambda (integer) ;; http://www.iki.fi/kt/ 
   (coerce (loop for i upfrom 0 by 8 below (integer-length integer)
                 collect (code-char (ldb (byte 8 i) integer))) 'string))
 100291759904362517251920937783274743691485481194069255743433035)
From: Kaz Kylheku
Subject: Re: Hack: dynamically discovering how to generate unquote and unquote-splicing.
Date: 
Message-ID: <cf333042.0303250959.7e109d5a@posting.google.com>
···@ashi.footprints.net (Kaz Kylheku) wrote in message news:<····························@posting.google.com>...
[ snip ]
> 
>   (defun unquote-splicing (arg)
>     (replace-tree uqs-form sym arg)))

[ snip ]
 
> ``,',(mapcar #'unquote-splicing '(a b c d)) 
 
>   ==>  `(,@A ,@B ,@C ,@D)
> 
> ``,',(mapcar #'unquote '(a b c d))
> 
>   ==>  `(,A ,B ,C ,D)

Now that I'm a grandmaster backquote hacker, I see the error of my
ways. There is in fact a standard way to get the above behaviors.

The audience is well advised to stand back at least five meters and
avoid gazing directly while I perform the next two blinding
expansions:

  ``(,,@'(a b c d))

  ==> `(,A ,B ,C ,D) ;; or equivalent code, who cares.

  ``(,@,@'(a b c d))

  ==> `(,@A ,@B ,@C ,@D) ;; or equivalent code.

So for these cases at least, there is no need for my hack; you do have
a way to generate a backquote form (or equivalent code) which contains
a variable number of unquotes, or splicing unquotes. This reduces the
need to have a list-based target syntax for constructing backquote
code.

I had no idea that such a distributive law existed to endow spliced
forms with unquotes; very handy indeed.

Oh yeah, and my trick did not actually work in CLISP, because its
backquote implementation (the old one, not mine! :) performs the
backquote expansion in the reader. The backquote macro is just a cheat
which just pulls a ready-made expansion from its sleeve, expecting the
reader assistant to have placed it there prior to the act. ;)