Open tfeb opened 2 years ago
That does not look like a valid d-l-l.
It is a valid destructuring-bind
lambda list: the syntax productions in the spec for several cases of lambda lists are at best confusing and at worst wrong: you need to look at the normative text, not them.
From 3.4.4.1:
Anywhere in a macro lambda list where a parameter name can appear, and where ordinary lambda list syntax (as described in Section 3.4.1 (Ordinary Lambda Lists)) does not otherwise allow a list, a destructuring lambda list can appear in place of the parameter name. When this is done, then the argument that would match the parameter is treated as a (possibly dotted) list, to be used as an argument list for satisfying the parameters in the embedded lambda list. This is known as destructuring.
And from 3.4.5:
Destructuring lambda lists are closely related to macro lambda lists; see Section 3.4.4 (Macro Lambda Lists). A destructuring lambda list can contain all of the lambda list keywords listed for macro lambda lists except for
&environment
, and supports destructuring in the same way. Inner lambda lists nested within a macro lambda list have the syntax of destructuring lambda lists.
(My emphasis).
This means, in effect, that anywhere a required variable is expected you can have a complete recursive lambda list (excepting &environment
I assume as that makes no sense there).
You could also just try destructuring-bind
:
(destructuring-bind (a (b)) '(1 (2))
(print a)
(print b))
Hmmm
If you are unfamiliar with destructuring-bind
it is also worth reading the issue that originally introduced it as well as this one.
I keep it open. I welcome pull requests
@tfeb: I think the fundamental issue here is that LAMBDA-LIST
only looks at a single level of expansion, and any subpatterns are treated as Trivia patterns, rather than destructuring lambda sub-list, as would be expected. I defined my own pattern to make LAMBDA-LIST
's syntax less annoying while still allowing an escape hatch to use arbitrary Trivia patterns:
;; This is a pattern that expands to lambda-list. Sub-patterns will also be expanded to
;; lambda-list, UNLESS they start with &, in which case they will be regular Trivia
;; patterns. This essentially makes the & pattern a toggle to go in and out of lambda-list
;; syntax
(defpattern & (&rest args)
,@(loop for arg in args
collect
(match arg
((or nil
(list 'quote _)
(not (satisfies listp)))
arg)
((list* '& rest) rest)
(_ `(& ,@arg)))))
Example usage
(match '(defun foo 13)
((& 'defun name (& or ; <-- escape to Trivia OR here
(list x y)
(and x (< 42))))
(values name x y)))
(match '(foo (bar baz) :quux 42)
((& name (var default) &key quux)
(values name default quux)))
I don't know whether this is the right way of implementing patterns (there don't seem to be any docs on that, so I was just doing whatever seemed most obvious), but it seems to work.
I don't know if the lambda list parser is meant to support these. The source sort of implies it does (
compile-destructuring-pattern
, for instance), but it doesn't:fails. I couldn't find anything in the documentation.