[Sbcl-devel] Another "technically" broken usage of backquote

Hi Alexander,
Not having heard a response to my prior email, I'd like to point out a
different unportable assumption in 'cl-larval'.
In your RESUBSTITUTE-LAMBDA-LIST there is a usage that does not adhere to
the spirit of the following clarifying remark in Appendix C to CLtL2:
"In general, Common Lisp guarantees the result of an expression with
backquotes nested to depth *k* only after *k* successive evaluations have
been performed; the results after fewer than *k* evaluations are
implementation-dependent"
The code fragment below will not work in a pending release of SBCL because
it relies on a particular shape of a doubly-backquoted expression after
only 1 evaluation. REQ-SUB, OPT-SUB, etc are each computed from an
expression of depth 2. The LET binding of BASE-LST attempts to take CDR of
REQ-SUB, etc.
(defun resubstitute-lambda-list (lambda-list)
"Deduce a comma-backquote expression needed to properly insert given
lambda list into another call.
'(a b &optional c &rest d) -> `(,a ,b ,c ,@d)"
(multiple-value-bind (required optional rest keys)
(alexandria:parse-ordinary-lambda-list lambda-list)
(cond ((cl:and optional keys) (error "This routine does not support
mixing of &optional with &keys"))
((cl:and rest keys) (error "This routine does not support
mixing of &rest and &keys"))
(t (let ((req-sub ``(,,@required))
(opt-sub ``(,,@(mapcar #'car optional)))
(key-sub (mapcan (lambda (x)
(cdr ``(,',(caar x) ,,(cadar x))))
keys))
(rest-sub rest))
(let ((base-lst ``(,,@(cdr req-sub) ,,@(cdr opt-sub)
,,@key-sub)))
(if rest-sub
`(append ,base-lst ,rest-sub)
base-lst))))))))
I understand what you want: a form that "looks like" a person wrote it
using backquote. But you can't do that in Common Lisp.
Common Lisp code offers no portably means to produce a backquoted form
other than by going through the Lisp reader.
This is in contrast to the specification for the Scheme language which
mandates (or at least very strongly suggests) a particular mechanism.
As such, you should produce an s-expression using primitives LIST and
APPEND. The effect will be the same. In other words,
(resubstitute-lambda-list '(a b &key foo)) => (LIST A B :FOO FOO)
instead of producing `(,A ,B ,C :FOO ,FOO) through a technically
impermissible mechanism that accidentally works at present.
Doug

Thread view

Hi Alexander,
Not having heard a response to my prior email, I'd like to point out a
different unportable assumption in 'cl-larval'.
In your RESUBSTITUTE-LAMBDA-LIST there is a usage that does not adhere to
the spirit of the following clarifying remark in Appendix C to CLtL2:
"In general, Common Lisp guarantees the result of an expression with
backquotes nested to depth *k* only after *k* successive evaluations have
been performed; the results after fewer than *k* evaluations are
implementation-dependent"
The code fragment below will not work in a pending release of SBCL because
it relies on a particular shape of a doubly-backquoted expression after
only 1 evaluation. REQ-SUB, OPT-SUB, etc are each computed from an
expression of depth 2. The LET binding of BASE-LST attempts to take CDR of
REQ-SUB, etc.
(defun resubstitute-lambda-list (lambda-list)
"Deduce a comma-backquote expression needed to properly insert given
lambda list into another call.
'(a b &optional c &rest d) -> `(,a ,b ,c ,@d)"
(multiple-value-bind (required optional rest keys)
(alexandria:parse-ordinary-lambda-list lambda-list)
(cond ((cl:and optional keys) (error "This routine does not support
mixing of &optional with &keys"))
((cl:and rest keys) (error "This routine does not support
mixing of &rest and &keys"))
(t (let ((req-sub ``(,,@required))
(opt-sub ``(,,@(mapcar #'car optional)))
(key-sub (mapcan (lambda (x)
(cdr ``(,',(caar x) ,,(cadar x))))
keys))
(rest-sub rest))
(let ((base-lst ``(,,@(cdr req-sub) ,,@(cdr opt-sub)
,,@key-sub)))
(if rest-sub
`(append ,base-lst ,rest-sub)
base-lst))))))))
I understand what you want: a form that "looks like" a person wrote it
using backquote. But you can't do that in Common Lisp.
Common Lisp code offers no portably means to produce a backquoted form
other than by going through the Lisp reader.
This is in contrast to the specification for the Scheme language which
mandates (or at least very strongly suggests) a particular mechanism.
As such, you should produce an s-expression using primitives LIST and
APPEND. The effect will be the same. In other words,
(resubstitute-lambda-list '(a b &key foo)) => (LIST A B :FOO FOO)
instead of producing `(,A ,B ,C :FOO ,FOO) through a technically
impermissible mechanism that accidentally works at present.
Doug