1
0
Fork 0
cl-sites/HyperSpec-7-0/HyperSpec/Issues/iss130_w.htm
2024-04-01 10:24:07 +02:00

207 lines
15 KiB
HTML

<!-- Common Lisp HyperSpec (TM), version 7.0 generated by Kent M. Pitman on Mon, 11-Apr-2005 2:31am EDT -->
<HTML>
<HEAD>
<TITLE>CLHS: Issue DESTRUCTURING-BIND Writeup</TITLE>
<LINK HREF="../Data/clhs.css" REL="stylesheet" TYPE="text/css" />
<META HTTP-EQUIV="Author" CONTENT="Kent M. Pitman">
<META HTTP-EQUIV="Organization" CONTENT="LispWorks Ltd.">
<LINK REL=TOP HREF="../Front/index.htm">
<LINK REL=COPYRIGHT HREF="../Front/Help.htm#Legal">
<LINK REL=DISCLAIMER HREF="../Front/Help.htm#Disclaimer">
<LINK REL=PREV HREF="../Issues/iss129_w.htm">
<LINK REL=UP HREF="../Issues/iss130.htm">
<LINK REL=NEXT HREF="../Issues/iss131_w.htm">
</HEAD>
<BODY>
<H1><A REV=MADE HREF="http://www.lispworks.com/"><IMG WIDTH=80 HEIGHT=65 ALT="[LISPWORKS]" SRC="../Graphics/LWSmall.gif" ALIGN=Bottom></A><A REL=TOP HREF="../Front/index.htm"><IMG WIDTH=237 HEIGHT=65 ALT="[Common Lisp HyperSpec (TM)]" SRC="../Graphics/CLHS_Sm.gif" ALIGN=Bottom></A> <A REL=PREV HREF="../Issues/iss129_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Previous]" SRC="../Graphics/Prev.gif" ALIGN=Bottom></A><A REL=UP HREF="../Issues/iss130.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Up]" SRC="../Graphics/Up.gif" ALIGN=Bottom></A><A REL=NEXT HREF="../Issues/iss131_w.htm"><IMG WIDTH=40 HEIGHT=40 ALT="[Next]" SRC="../Graphics/Next.gif" ALIGN=Bottom></A></H1>
<HR>
<H2>Issue DESTRUCTURING-BIND Writeup</H2>
<PRE><B>Issue:</B> <A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A><P>
<B>Forum:</B> Cleanup<P>
<B>References:</B> <A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> (CLtL pp145-151),<P>
The <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> Facility (X3J13/89-004)<P>
<B>Category:</B> ADDITION<P>
<B>Edit history:</B> 24-Jan-89, Version 1 by Pitman<P>
25-Jan-89, Version 2 by Pitman<P>
29-Mar-89, Version 3, by Moon, amended based on poll<P>
<P>
<B>Problem Description:<P>
</B><P>
Common Lisp programmers have frequently complained that the<P>
destructuring facility used by <A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> is not made available<P>
for use in ordinary programming situations involving list data.<P>
<P>
The presence of a destructuring facility in the recently adopted<P>
<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> facility will be likely to make the absence of a separable<P>
destructuring facility all the more apparent.<P>
<P>
Prior to the introduction of <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> into Maclisp, many people wrote<P>
their own <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> macros. A popular expansion was in terms of a <A REL=DEFINITION HREF="../Body/m_do_do.htm#do"><B>DO</B></A><P>
which did not iterate. eg,<P>
(<A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> ((A 3)) (+ A A)) ==&gt; (<A REL=DEFINITION HREF="../Body/m_do_do.htm#do"><B>DO</B></A> ((A 3)) () (<A REL=DEFINITION HREF="../Body/m_return.htm#return"><B>RETURN</B></A> (+ A A)))<P>
While this practice `worked,' it was not perspicuous and contributed <P>
substantially to non-readability: not only were the macros hard to<P>
understand, but the surface interface itself was not standardized<P>
and varied in subtle ways. For example, some <A REL=DEFINITION HREF="../Body/s_let_l.htm#let"><B>LET</B></A> macros allowed <A REL=DEFINITION HREF="../Body/s_go.htm#go"><B>GO</B></A><P>
statements while others did not.<P>
<P>
There is now considerable danger that a lot of people will write<P>
<A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> variants in terms of a <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> expression that<P>
immediately returns.<P>
(<A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> ((A B) C) (FOO) (<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> A B C))<P>
==&gt; (<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> FOR ((A B) C) ON (FOO) <A REL=DEFINITION HREF="../Body/m_do_do.htm#do"><B>DO</B></A> (<A REL=DEFINITION HREF="../Body/m_return.htm#return"><B>RETURN</B></A> (<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> A B C)))<P>
Since the destructuring offered by <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> is different in subtle ways<P>
from the destructuring offered by <A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> in implementations<P>
offering that primitive natively, gratuitous headaches could result.<P>
<P>
<B>Proposal (DESTRUCTURING-BIND:NEW-MACRO):<P>
</B><P>
Provide a macro called <A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> which behaves like the<P>
destructuring bind in <A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A>. Specifically...<P>
<P>
<A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> lambda-list expression {decl}* {form}* [Macro]<P>
<P>
Binds the variables specified in LAMBDA-LIST to the corresponding<P>
values in the tree <A REL=DEFINITION HREF="../Body/f_docume.htm#structure"><B>structure</B></A> resulting from evaluating EXPRESSION,<P>
then evaluates the FORMS in the body.<P>
<P>
Anywhere in the LAMBDA-LIST where a parameter name may appear, and<P>
where ordinary lambda-list syntax (as described in CLtL section 5.2.2)<P>
does not otherwise allow a list, a lambda-list may appear in place of<P>
the parameter name. When this is done, then the argument form that<P>
would match the parameter is treated as a (possibly dotted) list, to<P>
be used as an argument forms list for satisfying the parameters in<P>
the embedded lambda-list.<P>
<P>
If any of the <A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> list keywords <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;OPTIONAL</B></A>, <A REL=DEFINITION HREF="../Body/03_da.htm#AMrest"><B>&amp;REST</B></A>, <A REL=DEFINITION HREF="../Body/03_da.htm#AMkey"><B>&amp;KEY</B></A>,<P>
<A REL=DEFINITION HREF="../Body/03_da.htm#AMallow-other-keys"><B>&amp;ALLOW-OTHER-KEYS</B></A> and <A REL=DEFINITION HREF="../Body/03_da.htm#AMaux"><B>&amp;AUX</B></A> appears in the <A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> list, it is treated<P>
as with any other lambda-list.<P>
<P>
If the <A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> list keyword <A REL=DEFINITION HREF="../Body/03_dd.htm#AMbody"><B>&amp;BODY</B></A> appears, it is treated as a synonym<P>
for <A REL=DEFINITION HREF="../Body/03_da.htm#AMrest"><B>&amp;REST</B></A>.<P>
<P>
The <A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> list keyword <A REL=DEFINITION HREF="../Body/03_dd.htm#AMenvironment"><B>&amp;ENVIRONMENT</B></A> is not allowed.<P>
<P>
If the <A REL=DEFINITION HREF="../Body/a_lambda.htm#lambda"><B>lambda</B></A> list keyword <A REL=DEFINITION HREF="../Body/03_dd.htm#AMwhole"><B>&amp;WHOLE</B></A> appears, it must be followed by a<P>
single variable that is bound to the entire expression at the current<P>
level. <A REL=DEFINITION HREF="../Body/03_dd.htm#AMwhole"><B>&amp;WHOLE</B></A> and its following variable should appear first in the<P>
list, before any other parameter or lambda-list keyword.<P>
<P>
It is also permissible for any level of the LAMBDA-LIST to be dotted,<P>
ending in a parameter name. This situation is treaed exactly as if<P>
the aprameter name that ends the list had appeared preceded by <A REL=DEFINITION HREF="../Body/03_da.htm#AMrest"><B>&amp;REST</B></A><P>
in a proper list. For example, the notation (X Y . Z) is equivalent<P>
to (X Y <A REL=DEFINITION HREF="../Body/03_da.htm#AMrest"><B>&amp;REST</B></A> Z).<P>
<P>
If the result of evaluating the expression does not match the <P>
destructuring pattern, an error should be signaled. <P>
<P>
<B>Test Case:<P>
</B><P>
(<A REL=DEFINITION HREF="../Body/m_defun.htm#defun"><B>DEFUN</B></A> IOTA (N) (<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> FOR I FROM 1 TO N COLLECT I)) ;helper<P>
<P>
(<A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> ((A <A REL=DEFINITION HREF="../Body/03_da.htm#AMoptional"><B>&amp;OPTIONAL</B></A> (B 'BEE)) ONE TWO THREE)<P>
`((ALPHA) ,@(IOTA 3))<P>
(<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> A B THREE TWO ONE))<P>
=&gt; (ALPHA BEE 3 2 1)<P>
<P>
<B>Rationale:<P>
</B><P>
The proposal directly addresses the stated problem, and is current practice<P>
in numerous implementations. Our charter effectively dictates that where<P>
feasible we should try to head off the widespread development of uselessly<P>
different variants of commonplace tools.<P>
<P>
The intent of the specification is to make <A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> lambda-lists<P>
compatible with inner-list elements of a macro lambda-list.<P>
<P>
<B>Current Practice:<P>
</B><P>
Symbolics Genera, Envos Medley, TI Explorer, and Lucid CL all offer<P>
<A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A>, though the details vary slightly.<P>
<P>
The <A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> offered by Symbolics Genera signals an error if<P>
the pattern is not matched. The TI Explorer version does not.<P>
<P>
<B>Cost to Implementors:<P>
</B><P>
Very small. In most cases, it's a matter of renaming and/or exporting an<P>
already existing symbol. In a few cases, a very small amount of <P>
`program interface' code would have to be written.<P>
<P>
<B>Cost to Users:<P>
</B><P>
None. This is an upward compatible change.<P>
<P>
<B>Cost of Non-Adoption:<P>
</B><P>
Loss of the Benefits and Aesthetics cited below.<P>
<P>
<B>Benefits:<P>
</B><P>
Users will get a powerful feature they have asked for on many occassions.<P>
<P>
In implementations which `autoload' code, it would be better for this<P>
support to be separable so that people could do <A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A><P>
without demand loading all other <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> support.<P>
<P>
<B>Aesthetics:<P>
</B><P>
Defining this macro centrally for the Common Lisp community will reduce<P>
subtle deviations, which will in turn have positive aesthetic impact.<P>
<P>
<B>Discussion:<P>
</B><P>
JonL observes that although <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> does destructuring, it can't directly<P>
make use of the <A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> interface suggested here.<P>
<P>
Pitman and Gray think a facility of this sort is a good idea, though<P>
obviously the details may still need a little fleshing out before the<P>
proposal is ready for vote.<P>
<P>
To date, the excuse for not satisfying this request has been a<P>
religious war between factions who want to destructure lists by<P>
writing<P>
(<A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> (var1 var2 var3) <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>exp</B></A> . body)<P>
and those who want to destructure lists by writing<P>
(<A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> (<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> var1 var2 var3) <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>exp</B></A> . body)<P>
<P>
The advantage of the former approach is that it is notationally<P>
concise for the common case of destructuring a list. The disadvantage<P>
is that it is not extensible to accomodate abstract kinds of<P>
destructuring.<P>
<P>
The advantage of the latter approach is that it allows interesting<P>
extensions that accomodate data-hiding, such as:<P>
(<A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> MAKE-FOO (<A REL=DEFINITION HREF="../Body/03_da.htm#AMrest"><B>&amp;REST</B></A> ELEMENTS) `(<A REL=DEFINITION HREF="../Body/a_list.htm#list"><B>LIST</B></A> ,@ELEMENTS))<P>
(<A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> (MAKE-FOO var1 var2 var3) <A REL=DEFINITION HREF="../Body/f_exp_e.htm#exp"><B>exp</B></A> . body)<P>
and later the ability to change the representation of a FOO without<P>
updating the associated binding forms. The disadvantage is that it<P>
is more verbose in the common case of destructuring a list, and still<P>
even more verbose for nested lists.<P>
<P>
Although destructuring has always existed in <A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A>, this has not<P>
been adequate precedence for deciding the outcome of the religious war<P>
because <A REL=DEFINITION HREF="../Body/m_defmac.htm#defmacro"><B>DEFMACRO</B></A> only needs to destructure programs, and programs are<P>
generally made up only of lists -- not arbitrary user-defined abstract<P>
data types.<P>
<P>
The lambda-list form of <A REL=DEFINITION HREF="../Body/m_destru.htm#destructuring-bind"><B>DESTRUCTURING-BIND</B></A> in this version is<P>
not completely compatible with the destructuring done by <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A><P>
in three areas: <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> allows <A REL=DEFINITION HREF="../Body/a_nil.htm#nil"><B>NIL</B></A> elements of a list to be ignored,<P>
<A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> does not allow &amp;-keywords, and <A REL=DEFINITION HREF="../Body/m_loop.htm#loop"><B>LOOP</B></A> destructuring ignores<P>
extra elements in the list being matched.<P>
<P>
</PRE>
<HR>
<A REL=NAVIGATOR HREF="../Front/StartPts.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Starting Points]" SRC="../Graphics/StartPts.gif" ALIGN=Bottom></A><A REL=TOC HREF="../Front/Contents.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Contents]" SRC="../Graphics/Contents.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Master.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Index]" SRC="../Graphics/Index.gif" ALIGN=Bottom></A><A REL=INDEX HREF="../Front/X_Symbol.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Symbols]" SRC="../Graphics/Symbols.gif" ALIGN=Bottom></A><A REL=GLOSSARY HREF="../Body/26_a.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Glossary]" SRC="../Graphics/Glossary.gif" ALIGN=Bottom></A><A HREF="../Front/X3J13Iss.htm"><IMG WIDTH=80 HEIGHT=40 ALT="[Issues]" SRC="../Graphics/Issues.gif" ALIGN=Bottom></A><BR>
<A REL=COPYRIGHT HREF="../Front/Help.htm#Legal"><I>Copyright 1996-2005, LispWorks Ltd. All rights reserved.</I></A><P>
</BODY>
</HTML>