jeff@aiai.edinburgh.ac.UK (Jeff Dalton) (04/11/91)
> Date: Thu, 4 Apr 91 13:01:00 PST > From: Jon L White <jonl%kuwait@lucid.com> > Message-Id: <9104042101.AA28583@kuwait> > To: Scheme@mc.lcs.mit.edu > In fact, Lisp/370 (predecessor to IBM's "Uncommon Lisp" called > LISP/VM) had automatic destructuring in every lambda argument > position, including the input arguments. By 1980, such an > extension was working in parts of MacLisp and in VAX/NIL. In > fact, it even "destructured" over vectors as well as lists; > [...] > This was particularly useful in the VAX/NIL compiler and assembler > where much more use was made of simple vectors rather than lists. > We even had a version that would destructure over DEFSTRUCT instances, > in the expectation that "objects" like vectors and structures would > displace lists as the more common data structure "of choice". I think this is an excellent example of how language design can affect the program development and debugging. (Which is not to say that many of the problems couldn't be solved by changing the development environment rather than the language.) One problem with destructuring (as opposed to pattern matching) is that it may not bother to check whether the object being destructured has the right shape. Of course, the corresponding problem with pattern matching is that it makes the check even when it is unnecessary. Another problem with patterns in general is that they usually do not respect the abstract structure of objects. If something is the third element of a list, a pattern will depend on it being the third element; if something is a slot of a struct, the pattern will depend on it being a slot (rather than being accessed some other way). This is a serious hassle in Prolog, where changing the structure of a term often requires changing patterns all over the program; and since the contents of terms are accessed positionally, it's easy to make a mistake. When people talk of the advantages of pattern-matching in Prolog and functional languages, they seldom mention that it has this disadvantage too. On the other hand, Lisp programmers often fail to make all the appropriate checks when examining a list. One often sees code that does something like (EQ (CAR EXPR) 'LAMBDA) and then assumes that the entire list is a proper lambda-expression, even when the list is accessed abstractly by calling functions such as LAMBDA-EXPR-PARAMETER-LIST (which just does a CADR). This suggests that it may be a good idea to have both destructuring and pattern-matching in Lisp, especially if something can be done about the problems mentioned above. Fortunately, something can be done (or so I'm told). For example, in functional languages it may be possible to define abstract "views" of objects for use in patterns. In Prolog, it may be possible to use code unfolding (read macro expansion) to define structures and patterns abstractly. But not all languages or implementations have such facilities, and (in Prolog at least), most programmers do not use them. This suggests that it helps to make such features a standard part of the language and so encourage their use. However, there are so many different ways to express patterns, with different advantages and disadvantages, that it is not clear that s single mechanism should be chosen. As JonL mentioned: > There was no technical difficulty in extending these ideas for Common > Lisp; but instead a debate arose over whether the pattern should be > defined to be a data object (i.e., a cons cell implying taking the CAR > and CDR of the input argument) or to be a program [i.e., for the above > example, write `(,a `#(,b ,c) . ,l) instead of (a #(b c) . l)]. The obvious answer in Lisp seems to be: write a macro to do whatever pattern-matching or destructuring you want. Unfortunately, it seems to be sufficiently hard to design a good macro that programmers often write out what they want by hand instead, even when they can make use of DESTRUCTURING-BIND. JonL writes: > I'm always having to intersperse lines of LET's amongst multiple > incarnations of DESTRUCTURING-BIND, as well as with MULTIPLE-VALUE-BIND's. Nonetheless, it should be possible for those so inclined to write _some_ macros. But then we often encounter another problem. For example, I wrote some macros that let me do such things as (defpat ((app () y) y) ((app (cons a x) y) (cons a (app x y)))) In the Scheme version I could also write (defpat ((app `() y) y) ((app `(,a . ,x) y) `(,a . ,(app x y)))) All I had to do was tell my macro how to compile (some cases of) quasiquote. But it's a pain to do this for Common Lisp, because backquote can expand into so many different things. Indeed, Common Lisp often fails to define what happens at the level just below the one you're meant to use, which makes it hard to define facilities that are similar but not identical to those offered as standard. GJC made this point about a month ago: From: gjc@mitech.COM Newsgroups: comp.lang.scheme Subject: Dear JONL: an ode to SQUID. Message-ID: <9103121148.AA07598@schizo> Date: 11 Mar 91 11:21:06 GMT The lack of SQUID and the foolishness of the "#," approach first struck me when dealing with the port of the FORTRAN->LISP translator from MACLISP to COMMON-LISP. By "#," approach I mean a tendency, first seen in the LISPMACHINE at MIT, to avoid an *OPEN* implementation policy, generally a SEMANTICS FIRST, then SYNTAX, has a tendency to be the most open, and instead go as soon as possible to some concept limited by the imagination of the lisp implementor of *EXACTLY* what the user will *REQUIRE*. One result is that many significantly complex applications, e.g. Macsyma, Fortran->Lisp, generally any imbedded language, depended critically on internal undocumented representations (e.g. the readmacro expansion of "#," and internal flags such as SI:COMPILER-XYX-FLAG) so as to be frustratingly fragile to systems changes. Nonetheless, I think the best way to proceed would be for people to write macros that they find useful, let others use them, and see what solutions evolve. -- jeff
davis@barbes.ilog.fr (Harley Davis) (04/12/91)
In article <12542.9104111347@subnode.aiai.ed.ac.uk> jeff@aiai.edinburgh.ac.UK (Jeff Dalton) writes: > From: Jon L White <jonl%kuwait@lucid.com> > This was particularly useful in the VAX/NIL compiler and assembler > where much more use was made of simple vectors rather than lists. > We even had a version that would destructure over DEFSTRUCT instances, > in the expectation that "objects" like vectors and structures would > displace lists as the more common data structure "of choice". The obvious answer in Lisp seems to be: write a macro to do whatever pattern-matching or destructuring you want. Unfortunately, it seems to be sufficiently hard to design a good macro that programmers often write out what they want by hand instead, even when they can make use of DESTRUCTURING-BIND. JonL writes: > I'm always having to intersperse lines of LET's amongst multiple > incarnations of DESTRUCTURING-BIND, as well as with MULTIPLE-VALUE-BIND's. Nonetheless, I think the best way to proceed would be for people to write macros that they find useful, let others use them, and see what solutions evolve. I think a simple macro solution is largely sufficient. For example, we have a simple DESTRUCTURING-LET macro in our Lisp. In approximately 60,000 lines of Lisp kernel code, there are exactly four uses of this macro. We avoid extensive use of such a feature because there are very few list structures being passed around which need to be destructured. If we need to look at certain object components within a function, it is best to use accessors to avoid dependency on implementations of objects using particular slot names; in this case, LET is sufficient. -- Harley Davis -- ------------------------------------------------------------------------------ nom: Harley Davis ILOG S.A. net: davis@ilog.fr 2 Avenue Gallie'ni, BP 85 tel: (33 1) 46 63 66 66 94253 Gentilly Cedex, France
jonl%kuwait@lucid.COM (Jon L White) (04/13/91)
In isssue Scheme Digest V3 #184, Jeff Dalton recounts the ways that LET, DESTRUCTURING-BIND, and MULTIPLE-VALUE-BIND could be unified by a single user-defined macro: Nonetheless, I think the best way to proceed would be for people to write macros that they find useful, let others use them, and see what solutions evolve. I know this sort of topic has already been flamed-out on this list, but the irresitable force of macro power does come up against the immovable object of a community of programmers. That is to say, as long as I was working only by myself, or with a VERY small set of hackers, Jeff's suggestion for extra macrofication works fine. But somehere around the 20-person "industrial quality" project you find that the number of idiosyncratic, personalized syntax macros is too large for anyone to comprehend. It just takes one conservative member of the team to demand that no macros be used for trivial extensions; and this rules out the one-liner JONL-BIND in favor of the three-lines involving LET, DESTRUCTURING-BIND, and MULTIPLE-VALUE-BIND. The above paragraph is based on hard experience (my own) with a group considerably smaller than 20. Of course, it is easier to bear if all 20 persons believe that the macro in question is about to be "a standard" in the language. (This may explain why there are so many constructs being suggested for standardization; but let us drink no standards before their time.) -- JonL --
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (04/15/91)
In article <12542.9104111347@subnode.aiai.ed.ac.uk>, jeff@aiai.edinburgh.ac.UK (Jeff Dalton) writes: > Another problem with patterns in general is that they usually do not > respect the abstract structure of objects. If something is the third > element of a list, a pattern will depend on it being the third > element; if something is a slot of a struct, the pattern will depend > on it being a slot (rather than being accessed some other way). This > is a serious hassle in Prolog, where changing the structure of a term > often requires changing patterns all over the program; and since the > contents of terms are accessed positionally, it's easy to make a > mistake. > When people talk of the advantages of pattern-matching in Prolog and > functional languages, they seldom mention that it has this disadvantage > too. (Self-advertisement: "The Craft of Prolog" _does_ talk about this and what to do about it.) A possible answer in Lisp-like languages would be to introduce a new form (define-pattern (<name> <parameter>...) <simple backquote expression>) where <simple backquote expressions> are sufficiently restricted for a simple program to figure out how to invert them (say: each <parameter> name must appear exactly once in the pattern, ,@ may appear only at the end of a list, something like that). One also introduces a new , variant: ,=(<pattern name> <backquote expression>...). If I used (define-pattern (assoc-link Key Val Rest) `((,Key ,@Val) ,@Rest)) then (let ((foo `,=(assoc-link foo 9 ,bar))) ...) would have the effect of (let ((foo `((foo . 9) ,@bar))) ...) and (destructure `,=(assoc-link ,k ,v ,bar) foo ...) would have the effect of (destructure `((,k ,@v) ,bar) foo ...) It's certainly doable. -- It is indeed manifest that dead men are formed from living ones; but it does not follow from that, that living men are formed from dead ones. -- Tertullian, on reincarnation.
mkatz@garlic.stanford.EDU (Morris Katz) (04/15/91)
Date: Fri, 12 Apr 91 18:36:05 PDT From: Jon L White <jonl%kuwait@lucid.com> In isssue Scheme Digest V3 #184, Jeff Dalton recounts the ways that LET, DESTRUCTURING-BIND, and MULTIPLE-VALUE-BIND could be unified by a single user-defined macro: Nonetheless, I think the best way to proceed would be for people to write macros that they find useful, let others use them, and see what solutions evolve. I know this sort of topic has already been flamed-out on this list, but the irresitable force of macro power does come up against the immovable object of a community of programmers. That is to say, as long as I was working only by myself, or with a VERY small set of hackers, Jeff's suggestion for extra macrofication works fine. But somehere around the 20-person "industrial quality" project you find that the number of idiosyncratic, personalized syntax macros is too large for anyone to comprehend. It just takes one conservative member of the team to demand that no macros be used for trivial extensions; and this rules out the one-liner JONL-BIND in favor of the three-lines involving LET, DESTRUCTURING-BIND, and MULTIPLE-VALUE-BIND. I sure hope they don't feel the same way about procedures. :-) If not, I think that they should consider for a while why procedural abstraction is acceptable, but abstration using macros is not. I suspect that the answer has more to do with documentation conventions and other development environment considerations than anything to do with language semantics, per se. If my suspicion is correct, then I advocate fixing our tools rather than changing the language. The above paragraph is based on hard experience (my own) with a group considerably smaller than 20. Of course, it is easier to bear if all 20 persons believe that the macro in question is about to be "a standard" in the language. (This may explain why there are so many constructs being suggested for standardization; but let us drink no standards before their time.) The logical extension of this argument is CommonLisp. Dump so much in the language that noone can ever imagine extending it in any way. If you do find a way, just go to the CL standard committee and they will add it to the next release. :-) -------------------- Morry Katz katz@cs.stanford.edu --------------------
jonl%kuwait@lucid.COM (Jon L White) (04/16/91)
re: It just takes one conservative member of the team to demand that no macros be used for trivial extensions; and this rules out the one-liner JONL-BIND in favor of the three-lines involving LET, DESTRUCTURING-BIND, and MULTIPLE-VALUE-BIND. I sure hope they don't feel the same way about procedures. :-) If not, I think that they should consider for a while why procedural abstraction is acceptable, but abstration using macros is not. . . . I wouldn't be so sure about this. The problem is one of complexity -- current buzzword: MegaProgramming -- and not of whether the interface is procedureal, functional, meta (macros and "hooks"), or what-not. re: The logical extension of this argument is CommonLisp. Dump so much in the language that noone can ever imagine extending it in any way. If you do find a way, just go to the CL standard committee and they will add it to the next release. :-) Since you mention the word "release", I must assume you are referring to the history of the MIT Lisp Machine project, and its notable commercial follow-on (Symblics), wherein new and often incompatible "releases" occured nearly every six months. Indeed, in the time period between 1978 and 1985, one could substantiate the charge you make; but the X3J13 committee (for CL standards) has yet to make a "release". So how did Common Lisp come by the reputation you mention (I am, sadly, acknowledging a "ring of truth" if not complete factuality to your comment)? First, recall that Common Lisp is the evolutionary extension of a series of Lisps beginning with the historic "1.5" at MIT nearly 30 years ago -- progressing through CTSS Lisp (ever hear of the "Compatible Time Sharing System?"), PDP6 Lisp, PDP10 MacLisp, LispMachineLisp, SPICELisp, and so on. A bit of middle-aged fat is beginning to show. But perhaps more importantly is the influence during the early 1980's of the idea that "Lisp" is the world's best programming _environment_. A parallel with the Unix world is (1) a computer language usually known by it's one-letter name, (2) an enormous non-standard set of library routines and utilities [although some standards bodies are addressing this question.] It's probably too late for Common Lisp ever to go back to a pure "kernel" language idea, but some of the "stock hardware" vendors of Common Lisp implementations have indeed been trying to unbundle pieces of the MonsterLispMachine inheritance from the required part of a Lisp system. [Contact me privately for details on what is happening; or, contact your favorite vendor's salesman; but please try to resist any intrusion of a "Marketing Blitzkrieg" into this email list, as has already happend on some other lists.] -- JonL --
boley@cs.umn.edu (Daniel Boley) (04/16/91)
Is this too simple a way to destructure a list of values? Here we locally destructure the first 3 elements of the list multiple-values-as-a-list into 3 local variables and as well as getting the cdddr in rest. ; first define this simple fcn..... (define (give value form) ; give value to a function (apply form value)) ; use GIVE to destructure a list of multiple values... (give multiple-values-as-a-list (lambda (variable-1 variable-2 variable-3 . rest) expr-to-evaled-with-destructured-bindings)) ; A macro is unnecessary, but if you used a macro, it could look like... ; (this needs a better mnemonic name) (give-macro (variable-1 variable-2 variable-3 . rest) multiple-values-as-a-list expr-to-be-evaled-with-destructured-bindings) Of course, a single value handled this way will be a list of one item, so it won't be as transparent as MULTIPLE-VALUE-BIND, yet it seems so simple. By just extending the lambda form so that the list of formals can be a list of lists, one can make this quite general... - Dan Boley boley@cs.umn.edu
mkatz@garlic.stanford.EDU (Morris Katz) (04/16/91)
Date: 15 Apr 91 10:37:38 GMT From: "Richard A. O'Keefe" <ok@goanna.cs.rmit.oz.au> Organization: Comp Sci, RMIT, Melbourne, Australia In article <12542.9104111347@subnode.aiai.ed.ac.uk>, jeff@aiai.edinburgh.ac.UK (Jeff Dalton) writes: > Another problem with patterns in general is that they usually do not > respect the abstract structure of objects. If something is the third > element of a list, a pattern will depend on it being the third > element; if something is a slot of a struct, the pattern will depend > on it being a slot (rather than being accessed some other way). This > is a serious hassle in Prolog, where changing the structure of a term > often requires changing patterns all over the program; and since the > contents of terms are accessed positionally, it's easy to make a > mistake. > When people talk of the advantages of pattern-matching in Prolog and > functional languages, they seldom mention that it has this disadvantage > too. (Self-advertisement: "The Craft of Prolog" _does_ talk about this and what to do about it.) A possible answer in Lisp-like languages would be to introduce a new form (define-pattern (<name> <parameter>...) <simple backquote expression>) . . . For another pattern matching extension to Scheme see Erik Ruf's Stanford Computer Systems Lab Tech report "LogScheme: Integrating Logic Programming into Scheme" an earlier draft of which appeared in the proceedings of the 4th ACM Conference on Functional Programming Languages and Computer Architecture under the title "Nondeterminism and Unification in LogScheme". -------------------- Morry Katz katz@cs.stanford.edu --------------------
jeff@aiai.edinburgh.ac.UK (Jeff Dalton) (04/17/91)
I wrote: Another problem with patterns in general is that they usually do not respect the abstract structure of objects. Richard O'Keefe suggested a form (define-pattern (<name> <parameter>...) <simple backquote expression>) I've done something slightly different. I wanted to try patterns similar to those in functional languages where, say, (CONS A B) can be used as a pattern that mateches a pair, binding A to the car and B to the CDR. So I have a form (define-view <constructor> (<accessor> ...)) The view for a pair would be (define-view cons (car cdr)) But neither solution feels entirely "right" to me, which makes me think (hope?) better solutions must be possible. That's one reason I felt the best way to proceed would be for people to write macros that they find useful, let others use them, and see what solutions evolve. To which JonL replied: I know this sort of topic has already been flamed-out on this list, but the irresitable force of macro power does come up against the immovable object of a community of programmers. That is to say, as long as I was working only by myself, or with a VERY small set of hackers, Jeff's suggestion for extra macrofication works fine. But somehere around the 20-person "industrial quality" project you find that the number of idiosyncratic, personalized syntax macros is too large for anyone to comprehend. And later: The problem is one of complexity -- current buzzword: MegaProgramming -- and not of whether the interface is procedureal, functional, meta (macros and "hooks"), or what-not. I would, of course, agree that it would be a mistake for programmers working together on a project to use personal, idiosyncratic macros. But good macros should decrease complexity, and it is still worth asking: how do we get better macros? This is where the "evolution" comes in. The early stanges, at laast, can't happen in industrial projects, but those aren't the only programs being written. Indeed, some interesting results have already appeared. For example, we have extend-syntax for defining macros and the various iteration macros described in CLtL II. We can't yet tell whether they, or their successors, will ever be readily accpted in industrial projects; but I still think the development of better macros is an effort worth making. -- jeff