Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 27 Apr 87 15:09:04 EDT Date: Mon, 27 Apr 87 14:58:50 EDT From: Jonathan A Rees Subject: match questions To: cth@IUCS.CS.INDIANA.EDU cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Wed 22 Apr 87 14:53:10 est from Chris Haynes Message-ID: <191716.870427.JAR@AI.AI.MIT.EDU> Date: Wed, 22 Apr 87 14:53:10 est From: Chris Haynes 7. Should MATCH be required, optional, or "Yellow Pages". Yellow pages. Let's get macros into the language so that this is possible!  Received: from STONY-BROOK.SCRC.Symbolics.COM (TCP 30002424620) by MC.LCS.MIT.EDU 26 Apr 87 15:56:53 EDT Received: from RIO-DE-JANEIRO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 124764; Sun 26-Apr-87 15:55:20 EDT Date: Sun, 26 Apr 87 15:54 EDT From: Kent M Pitman Subject: match questions To: cth@iucs.cs.indiana.edu cc: rrrs-authors@mc.lcs.mit.edu In-Reply-To: The message of 22 Apr 87 15:53 EDT from Chris Haynes Message-ID: <870426155448.6.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM> When you say you think we want a matcher, does the "we" refer to Scheme designers or to Scheme users? In my experience, users want virtually anything that will save them work. So any user who's got a matching problem would want a matcher. Of course, users get to wipe clean their assumptions every time they start over on a new project so they tend to have a more short-sighted view of things. On the other hand, a language designer is pretty much stuck with anything he puts in his language forever after. For that reason, he must be more particular. If you're thinking of adding a match facility to Scheme, you must first decide at what level you were going to add it. If you add it as linguistic glue (as, for example, in Prolog), you have a lot of work ahead of you figuring out how to weave it into the fabric of the language so that it doesn't end up feeling hastily tacked on. If you just want to add a tool that isn't integrated at the glue level, you should be ready to justify why you chose to add that tool and not the myriad of other possible tools that Common Lisp and company have adopted while Scheme has steadfastly shunned as contrary to the goals of a simple and elegant language. By the way, Jonathan has convinced me that a graceful matcher is possible so I'm not trying to talk you completely out of it. I just think there's no good argument for it being anywhere but in the Yellow Pages unless you're willing to go the extra mile and make the language really use it at a very low level... and I don't see anyone going that extra mile (nor do I expect that if they did the others would accept it).  Received: from Sushi.Stanford.EDU (TCP 4402000065) by MC.LCS.MIT.EDU 24 Apr 87 21:18:56 EDT Date: Fri 24 Apr 87 18:22:11-PDT From: Andy Freeman Subject: Re: match questions To: wand%corwin.ccs.northeastern.edu@RELAY.CS.NET cc: rrrs-authors@MC.LCS.MIT.EDU, cth%indiana.csnet@RELAY.CS.NET In-Reply-To: Message from "wand%corwin.ccs.northeastern.edu@RELAY.CS.NET" of Fri 24 Apr 87 17:07:43-PDT Message-ID: <12297190001.12.ANDY@Sushi.Stanford.EDU> Before I forget. I don't think structures are a counter-proposal to matchers. They're for problems that matchers aren't the right tool for and are completely inappropriate for the things that matchers do best. Actually, I was serious about the hokey accessor syntax award. I don't like it, there are lots of better syntaxes, but it does illustrate my point. The following defstruct only defines a predicate function and accessor syntax. (defstruct (branch left right) (left (or leaf branch)) (right (or leaf branch))) The predicate is branch? and the accessor syntax "verb" is branch. (branch tree left) is syntax for accessing the left of tree's value (which is a branch), but left isn't evaluated. (This order obviously has problems.) Left is recognized as a field name in that position by the branch accessor syntax. Other structs can have a left and left can be used for other purposes without confusion. Yes, each instance of a struct in my proposal does add three names to the namespace, but that's independent of the number of fields. (I didn't mention creators.) On the other hand, one could define a create syntax, (create branch left x right y), so that no creator name is added to the namespace. This create would be global syntax that recognizes struct names and fields. Similar games can be played with accessor syntax and predicates so that no names are added to the namespace by a definition. (I think they'd be silly, but ....) I don't understand the less-local objection. Either you know what you want out of the struct or you don't. Matchers rely on positional notation, structures rely on names. The real bug with my proposal is that any user of a structure can see everything in it; matchers have this problem too. "private" fields and the like are the solution, but I don't have a syntax. -andy -------  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 24 Apr 87 19:53:45 EDT Received: from relay2.cs.net by RELAY.CS.NET id aa00914; 24 Apr 87 20:05 EDT Received: from northeastern.edu by RELAY.CS.NET id ab03143; 24 Apr 87 20:00 AST Received: from corwin.ccs.northeastern.edu by nuhub.acs.northeastern.edu; Fri, 24 Apr 87 16:37 EST Received: by corwin.CCS.Northeastern.EDU (5.51/5.17) id AA04605; Fri, 24 Apr 87 10:31:40 AST Date: Fri, 24 Apr 87 10:31:40 AST From: wand%corwin.ccs.northeastern.edu@RELAY.CS.NET To: ANDY@SUSHI.STANFORD.EDU Cc: rrrs-authors@MC.LCS.MIT.EDU, cth%indiana.csnet@RELAY.CS.NET In-Reply-To: "Andy Freeman"'s message of Thu 23 Apr 87 15:36:18-PDT Subject: match questions Much as I like pattern matching as proposed by Chris, I think Andy may be on to something, though I don't completely understand it. treenum ::= Leaf num | Branch treenum treenum sumtree :: treenum -> num sumtree (Leaf x) = x sumtree (Branch xt yt) = sumtree xt + sumtree yt To my mind, the following commonlispish program is superior. For one thing, I can change the things that are in a branch without changing the sumtree program. Note the absense of positional notation/ information. (defstruct (leaf weight) (weight number)) ;;; since this is lisp, type decls are optional (defstruct (branch left right) (right (or leaf branch)) (left (or leaf branch))) ; This may win the hokiest accessor syntax award but it does ; suggest an obvious extension if multiple values are introduced.... (define (sumtree tree) (cond ((leaf? tree) (leaf tree weight)) ((branch? tree) (+ (sumtree (branch tree left)) (sumtree (branch tree right)))) (else ))) I guess I don't completely understand this. If I understand it, the second defstruct exports the following global definitions: [Let's not argue about the word "global" and what happens if the defstruct appears in an interior scope, OK?] branch? branch left right I guess I don't understand why there is both "branch" and "left/right" here. If I understand it correctly, I couldn't have another defstruct that had a different "left". Is that right? What Chris and I most commonly use matching for is as a rough-and-ready device for decomposing variant record structures. In general, one needs an interface between the design of the record structure and the code that uses that design. There are a number of conflicting design goals: 1. Locality of reference. The code that uses the record should be readable without reference to a textually-distant definition of the record structure. 2. Control of the namespace. The interface should garbage as little of the global namespace as possible. Pattern-matching scores heavily on both these counts; in particular, it uses no globally named access functions. Andy's proposal seems deficient, though again I'm not sure I understand it. 3. Modifiability. Changes in the record definition should not require rewriting the code that uses that definition. This is where pattern-matching loses: user code must be rewritten whenever fields are reordered or added. This is where defstruct's (eg Common Lisp's) are on the right track. Reordering or adding fields does not require recoding of user functions. Common Lisp defstruct (and Chez Scheme define-structure) also do pretty well on the side of not garbaging the global namespace: the names of the access functions form a distinguished sublanguage (identifiers of the form structname-fieldname, though I'd probably prefer structname->fieldname), so the only "really global" identifiers established are structname (and structname?). I think it is possible to get something at a higher level than defstruct that still has the right properties, while increasing locality of reference, but I haven't figured it out well enough to share it quite yet. --Mitch  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 23 Apr 87 22:54:52 EDT Date: Thu, 23 Apr 87 23:12:36 EDT From: Jonathan A Rees Subject: The verdict: 27-28 June To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <190062.870423.JAR@AI.AI.MIT.EDU> Many more people seem to dislike 2-3 July than dislike 27-28 June. Therefore, since no one else seems to be stepping forward to take responsibility, I have reserved the MIT EECS Dept.'s Grier Room for 9 am to 5 pm on Saturday 27 and Sunday 28 June. My apologies to those of you who can't make it then. You should feel free to try to work out a different date with the group if you want; I certainly have no more claim to authority than anyone else on this matter, nor do I want it.... Jonathan  Received: from Sushi.Stanford.EDU (TCP 4402000065) by MC.LCS.MIT.EDU 23 Apr 87 20:02:16 EDT Date: Thu 23 Apr 87 15:36:18-PDT From: Andy Freeman Subject: Re: match questions To: rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Message from "Chris Haynes " of Thu 23 Apr 87 14:33:37-PDT Message-ID: <12296897659.45.ANDY@Sushi.Stanford.EDU> I think that all of the scheme match proposals I've seen during the last two weeks, as well as Miranda and other languages favored by the functional programming community and logic programming languages (any other oxen to gore?), confuse some things that I work very hard to keep separate. Unfortunately, I don't have a word for them, but I can illustrate my point with one of Wadler's examples. He wrote: treenum ::= Leaf num | Branch treenum treenum sumtree :: treenum -> num sumtree (Leaf x) = x sumtree (Branch xt yt) = sumtree xt + sumtree yt To my mind, the following commonlispish program is superior. For one thing, I can change the things that are in a branch without changing the sumtree program. Note the absense of positional notation/ information. (defstruct (leaf weight) (weight number)) ;;; since this is lisp, type decls are optional (defstruct (branch left right) (right (or leaf branch)) (left (or leaf branch))) ; This may win the hokiest accessor syntax award but it does ; suggest an obvious extension if multiple values are introduced.... (define (sumtree tree) (cond ((leaf? tree) (leaf tree weight)) ((branch? tree) (+ (sumtree (branch tree left)) (sumtree (branch tree right)))) (else ))) (Yes, some people want to push the cond into the function calling mechanism but since I usually have procedures with multiple arguments, I don't like to go that far.) One "feature" of this idea is that it doesn't support "generic" information, ie things that are common to a number of different "type", such as printer, since the accessors specify the "type." This suggests that T's limited object-oriented style is a big win because it allows (left tree) to do the right thing even though lots of "types" have a "left." On the other hand, perhaps common/inherited components are rare enough that they should be handled via a separate mechanism. I agree that T's destructure, and match-like generalizations of it, are great, but they're for different problems. I'd rather use a different hammer for compound-object problems. -andy -------  Received: from iucs.cs.indiana.edu (TCP 30003147315) by MC.LCS.MIT.EDU 23 Apr 87 17:02:54 EDT Date: Thu, 23 Apr 87 16:20:27 est From: Chris Haynes To: rrrs-authors@mc.lcs.mit.edu Subject: match questions From: "Guillermo J. Rozas" I'm sorry, but I fail to see the point of a MATCH extension to the language. Every time I've wanted pattern matching, I've built my own, because the constraints and requirements were different, so a fixed utility would do me no good. My experience, which reflects what I've done with Scheme (I've never written an emacs), is simply different. I've seldom felt the need for optional arguments, and never a pressing need for more than the '.' rest feature we already have. Thus my don't care attitude toward the optional argument proposals, except for a general desire that all that mechanism not be added to the language when I don't expect to use it. But I respect the desires of the many who do use optional arguments, at least as long as the facility is optional. What I don't understand is why more people don't find use for MATCH (or maybe they do, and we just haven't heard from them). I find a constant need for destructuring (I hate car/cdr chains), and frequent need for matching. Many a COND expression would look better if it were a MATCH expression. I, and others here, have found the simple sort of match facility I've outlined to be quite adequate for almost all our needs. And people seldom build their own matches, but instead use car/cdr chains and COND at every turn. The functional programming community (broadly speaking, including languages like ML) certainly goes for matching in a big way (and not optional arguments). Why is the Lisp community traditionally so different? We might as well try to agree on a UNIFY facility. It would probably be more useful. Not at all. Unification requires logic variables, which are a significant semantic addition to any language (whereas MATCH is semantically trivial). Also, it isn't clear how much unification is worth without backtracking (multiple values, Prolog style), and that is pretty clearly a step into another language. Chris  Received: from iucs.cs.indiana.edu (TCP 30003147315) by MC.LCS.MIT.EDU 23 Apr 87 16:25:00 EDT Date: Thu, 23 Apr 87 15:29:04 est From: Chris Haynes To: philbin-jim@YALE.ARPA Cc: rrrs-authors@mc.lcs.mit.edu In-Reply-To: James F Philbin's message of Thu, 16 Apr 87 17:31:11 EDT <8704162131.AA11569@yale-celray.arpa> Subject: Scheme pattern matcher For those who would like to look at and perhaps try out a simple match facility, here's mine. The Scheme84 MATCH has a bit different syntax and a very different implementation, due to Bruce Duba. He uses Eugene's extend-syntax in clever ways to compile MATCH expressions to conditional expressions (rather than the interpretive approach I use). It is available via anonymous ftp as part of pub/scheme84/synstd.s on cs.indiana.edu. ;; match: Chez Scheme pattern matching and destructuring facility. ;; ;; Author: Chris Haynes (haynes@cs.indiana.edu) ;; ;; ;; (match ( ...) ...) ;; ;; ::= ;; | | | | | (quote ) ;; | #( ...) ;; | #& ; Chez Scheme box (reference) ;; | (? ) ;; | ( ...) ;; | ( ... . ) ;; ;; MATCH is a fairly general pattern matching and destructuring ;; facility. is evaluated and its value is matched against the ;; s in order until a matching pattern is found. An error is ;; signaled if no pattern matches. When a match is found, the value ;; of is destructured with the variables in the matching pattern ;; bound to the corresponding components of 's value. The ;; expressions of the matching pair are then evaluated in an ;; environment formed by extending the environment of the MATCH ;; expression with these new bindings. The value of the last ;; expression is returned as the value of the MATCH expression. ;; ;; The symbols QUOTE and ? are used in patterns to identify literals ;; and predicate tests, so they may not be used as pattern variables. ;; Number, string, boolean, character and quoted literal s must ;; be EQUAL? to corresponding components of s value, or the ;; pattern fails. expressions should evaluate (in the ;; environment of the MATCH expression) to unary functions that are ;; applied to the corresponding component of s value when ;; matching of the ? pattern is attempted. If the predicate returns ;; false, the pattern fails. Otherwise, the value applied to the ;; predicate is matched against the pattern following the predicate. ;; ;; ;; (match '(2 . 3) ((a . b) (* a b))) ==> 6 ;; ;; (match '(1 2) ((a) a) ((a b) (+ a b)) (c c)) ==> 3 ;; ;; (match (list 33 "string" #\c (not #t) #(1 2)) ;; ((33 "string" #\c #f #(a b)) (cons a b))) ==> (1 . 2) ;; ;; (let ((num 3)) ;; (match (cons 'x 4) ;; (((? (lambda (v) (or (symbol? v) (and (number? v) (= v num)))) ;; c) ;; . (? number? d)) (list c d)))) ==> (x 4) ;; ;; (match '(bar 3 4 5) ;; (('foo x y) (cons x y)) ;; (('bar x y . z) (list x y z)) ;; (else (error "didn't match: " else))) ==> (3 4 (5)) ;; (define matcher (lambda (exp pairs-info) (if (null? pairs-info) (error 'match "no pattern for: ~s" exp) (let ((pat (caar pairs-info)) (fn (cadar pairs-info)) (preds (cddar pairs-info)) (fail (lambda () (matcher exp (cdr pairs-info))))) (let loop ((exp exp) (pat pat) (succeed (lambda (args) (apply fn args)))) (cond ((or (null? pat) (number? pat) (char? pat) (string? pat) (boolean? pat)) (if (equal? pat exp) (succeed '()) (fail))) ((symbol? pat) (succeed (list exp))) ((box? pat) (if (box? exp) (loop (unbox exp) (unbox pat) succeed) (fail))) ((vector? pat) (if (vector? exp) (let ((len (vector-length pat))) (if (= len (vector-length exp)) (let inner ((n 0) (args '())) (if (= n len) (succeed args) (loop (vector-ref exp n) (vector-ref pat n) (lambda (car-args) (inner (+ 1 n) (append! args car-args)))))) (fail))) (fail))) ((eq? (car pat) 'quote) (if (equal? (cadr pat) exp) (succeed '()) (fail))) ((eq? (car pat) '?) (if ((car preds) exp) (begin (set! preds (cdr preds)) (loop exp (caddr pat) succeed)) (fail))) ((pair? exp) (loop (car exp) (car pat) (lambda (car-args) (loop (cdr exp) (cdr pat) (lambda (cdr-args) (succeed (append! car-args cdr-args))))))) (else (fail)))))))) (define-macro! match (exp . pairs) (let ((ids&preds-of (lambda (pat) (let* ((preds '()) (ids (let loop ((pat pat)) (cond ((or (null? pat) (number? pat) (char? pat) (string? pat) (boolean? pat)) '()) ((symbol? pat) (list pat)) ((box? pat) (loop (unbox pat))) ((vector? pat) (loop (vector->list pat))) ((eq? (car pat) 'quote) '()) ((eq? (car pat) '?) (set! preds (cons (cadr pat) preds)) (loop (caddr pat))) (else (let ((cdrids (loop (cdr pat)))) (append! (loop (car pat)) cdrids))))))) (cons ids preds))))) `(matcher ,exp (list . ,(map (lambda (pair) (let ((pattern (car pair)) (body (cdr pair))) (let ((ids&preds (ids&preds-of pattern))) `(cons ',pattern (cons (lambda ,(car ids&preds) . ,body) (list . ,(cdr ids&preds))))))) pairs)))))  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 23 Apr 87 15:50:55 EDT Received: from relay2.cs.net by RELAY.CS.NET id ad20226; 23 Apr 87 15:53 EDT Received: from tektronix.tek.com by RELAY.CS.NET id bb08194; 23 Apr 87 15:45 AST Received: by tektronix.TEK.COM (5.51/6.20) id AA13695; Thu, 23 Apr 87 11:28:07 PDT Received: by tekchips.TEK.COM (5.31/6.19) id AA13316; Thu, 23 Apr 87 11:28:52 PDT Message-Id: <8704231828.AA13316@tekchips.TEK.COM> To: cth%indiana.csnet@RELAY.CS.NET Cc: rrrs-authors@MC.LCS.MIT.EDU, willc%tekchips.tek.com@RELAY.CS.NET Subject: Re: match questions In-Reply-To: Your message of Wed, 22 Apr 87 14:53:10 est. <8704230115.AA05069@tekchips.TEK.COM> Date: 23 Apr 87 11:28:50 PDT (Thu) From: willc%tekchips.tek.com@RELAY.CS.NET Chris's questions give me a welcome chance to express my personal views on this matter. 1. Do we want a match facility? No. 2. Given a match facility, do we need optional arguments? Yes. Optional arguments are in the standard library already, and that example encourages people to write new procedures with optional arguments. The problem is that optional arguments must now be implemented either by rest arguments, which leads to poor error-checking because few people take the trouble to check for excess arguments, or by implementation-specific and therefore non-portable hacks. Using rest arguments to implement optional arguments is also inefficient. The worst of it is that the inefficiency biases people toward omitting optional arguments, when people should be encouraged to write them explicitly: WRITE-CHAR with two arguments conses, but WRITE-CHAR with one argument doesn't. If you don't think that a single cons per character matters, then the implementation you've been using isn't fast enough. I would not be opposed to demoting the "." rest flag to optional or nonexistent status if it were replaced with #!optional and #!rest, or equivalent. 3. Should patterns be in read format (with quote), e.g. ('x 1 y), or in construction expression format, e.g. (list 'x 1 y)? Read format would be `(X 1 ,Y). The above "read format" corresponds to no existing syntax. It would be a new sublanguage, like Common Lisp's FORMAT though less silly. "Construction expression format" is sensible only if you have a meaningful notion of static type. Without static types, patterns based on construction expression format offer all the embarrassments of Common Lisp's SETF. For example, what would the pattern (LIST 'X 1 Y) mean inside (LET ((LIST VECTOR)) ...)? Even if you have static types, construction expression format generalizes only to free constructors, as even Philip Wadler observed in the SIGPLAN Notices article that seems to have given impetus to this particular crusade. 4. Can we define a good way of declaring additional constructors, to get more of an ML like matching mechanism? Sure, but first you have to turn Scheme into a statically typed language. Even then it would only work for free constructors like CONS, and would not work for constructors like ADJOIN. An ML-like matcher is far too much machinery when you consider that it does't generalize beyond a small set of rudimentary data types. 5. Do we want to be able to embed arbitrary predicates in patterns, and if so, with what syntax? No. To paraphrase Marie Antoinette, let them use COND. 6. Should the match facility be an abstraction (lambda) or local binding (let) form, or should it provide both? Neither. It would be ok as a library procedure. 7. Should MATCH be required, optional, or "Yellow Pages". Yellow pages, if at all. Unlike optional arguments, it can be implemented in terms of what we already have at no cost in efficiency or reliability. It is not a thing I need, and if I ever find myself wanting it I'd be happy to include it from a source library. By the way, I have written perhaps half a dozen specialized matchers for my own programs, some of them fairly powerful, but I don't believe the proposed facility would have saved me from writing any of them. My matchers have generally been written to simplify the construction of mini-compilers for application-specific languages. Thank you for requesting my opinions. Peace, Will  Received: from grape.ads.ARPA (TCP 1200400070) by MC.LCS.MIT.EDU 23 Apr 87 14:06:57 EDT Received: by hobbes.ads.arpa (3.2/SMI-3.2) id AA29550; Thu, 23 Apr 87 11:23:04 PDT Date: Thu, 23 Apr 87 11:23:04 PDT From: andy%hobbes@ads.ARPA (Andy Cromarty) Message-Id: <8704231823.AA29550@hobbes.ads.arpa> To: rrrs-authors@MC.LCS.MIT.EDU Subject: Re: match questions I agree with Jinx and CPH. Matching, special handling of optionals, etc. can be convenient when they happen to provide what you want, but let's get more experience with matching facilities within Scheme, and more reports of such experience from more people, before we commit to a specific construct (if any is needed at all). If we have a standard macro definition capability, and especially if we allow any token at all to be redefinable (including, e.g., LET), then there's no need to build matching facilities into the language definition. Advocates of alternative matching and destructuring techniques can build the macro packages and distribute them informally to entice the rest of us to adopt their view of the importance of such constructs as a part of the language. asc  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 23 Apr 87 12:23:04 EDT Date: Thu, 23 Apr 87 12:24:52 EDT From: Chris Hanson Subject: match questions To: cth@IUCS.CS.INDIANA.EDU cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Wed 22 Apr 87 14:53:10 est from Chris Haynes Message-ID: <189657.870423.CPH@AI.AI.MIT.EDU> I agree with Jinx. A match facility is neither needed nor is it a desirable addition to the core language. I find optional arguments useful but unnecessary.  Received: from geneva (TCP 2206400372) by MC.LCS.MIT.EDU 22 Apr 87 19:20:15 EDT Received: by GENEVA.AI.MIT.EDU; Wed, 22 Apr 87 17:39:43 est Date: Wed, 22 Apr 87 17:39:43 est From: jinx@GENEVA.AI.MIT.EDU (Guillermo J. Rozas) Message-Id: <8704222239.AA05975@geneva> To: cth@iucs.cs.indiana.edu Cc: rrrs-authors@mc.lcs.mit.edu In-Reply-To: Chris Haynes's message of Wed, 22 Apr 87 14:53:10 est <8704222223.AA05964@geneva> Subject: match questions Reply-To: jinx@zurich.ai.mit.edu 1. Do we want a match facility? No. Unless it involves adding no new special forms. I won't object to a couple of utility procedures in the Yellow pages for the people who use this sort of thing. 2. Given a match facility, do we need optional arguments? We don't need them as it is. I'd much rather agree on something for optional arguments (which I use regularly), than on some facility I find no use for. 3. Should patterns be in read format (with quote), e.g. ('x 1 y), or in construction expression format, e.g. (list 'x 1 y)? I could not care less. 4. Can we define a good way of declaring additional constructors, to get more of an ML like matching mechanism? I don't know. Whatever it is, I feel it should simultaniously define constructor, predicate and destructuring functions. The obvious approaches I've thought of seem a bit clunky, and I question whether we want to add that much mechanism to Scheme. Adding a match facility is adding too much mechanism as it is. 5. Do we want to be able to embed arbitrary predicates in patterns, and if so, with what syntax? I could not care less. 6. Should the match facility be an abstraction (lambda) or local binding (let) form, or should it provide both? The only way I'll be happy with it is if it involves no special forms. Then users can write their own syntactic extensions to make it convenient if they need it. 7. Should MATCH be required, optional, or "Yellow Pages". Definitely Yellow Pages if at all. It seems hard to come up with definitive answers to some of these questions. However, I don't see any indication that the issues here are deep, so we should be able to agree on something satisfactory without a whole lot of research. So let's try to do it in time for the July (?) meeting. I'm sorry, but I fail to see the point of a MATCH extension to the language. Every time I've wanted pattern matching, I've built my own, because the constraints and requirements were different, so a fixed utility would do me no good. We might as well try to agree on a UNIFY facility. It would probably be more useful.  Received: from iucs.cs.indiana.edu (TCP 30003147315) by MC.LCS.MIT.EDU 22 Apr 87 15:55:31 EDT Date: Wed, 22 Apr 87 14:53:10 est From: Chris Haynes To: rrrs-authors@mc.lcs.mit.edu Subject: match questions Here are some questions that we need to answer before adopting a matching facility, along with my answers. I hope they generate debate. 1. Do we want a match facility? YES, very much so. 2. Given a match facility, do we need optional arguments? No, but something like OPTIONALS might be in the Yellow Pages. In fact, we could get demote the '.' rest feature to optional status, or even eliminate it. (Yeh!) 3. Should patterns be in read format (with quote), e.g. ('x 1 y), or in construction expression format, e.g. (list 'x 1 y)? I currently favor read format, but not by much, and if we can get a satisfactory answer to the next question, I'd probably favor construction format. 4. Can we define a good way of declaring additional constructors, to get more of an ML like matching mechanism? I don't know. Whatever it is, I feel it should simultaniously define constructor, predicate and destructuring functions. The obvious approaches I've thought of seem a bit clunky, and I question whether we want to add that much mechanism to Scheme. Without this, the matching facility is pretty simple and does not clutter up the rest of the language. (In fact, it can eliminate the optional arguments clutter.) Still, it would be very nice and may well be worth the mechanism. I just don't want to see resistance to this mechanism nix agreement on a simpler match facility. 5. Do we want to be able to embed arbitrary predicates in patterns, and if so, with what syntax? Yes, but I don't feel strongly about this. The (? ) syntax I proposed isn't wonderful, but it does the job. Note that ? (and quote) may still be used as literals, e.g. ('? 'quote foo). It is only their use as pattern variables that is prohibited. 6. Should the match facility be an abstraction (lambda) or local binding (let) form, or should it provide both? Local binding. A MATCH-LAMBDA form might be optional (I could certainly imagine wanting it), but it's probably better to have only one abstraction form, and keep it as simple as possible. If anyone wants MATCH-LAMBDA badly enough, it is easy to define given MATCH and any syntactic extension mechanism. 7. Should MATCH be required, optional, or "Yellow Pages". Optional, since it is not very hard to implement with required facilities, we want to keep the required base language simple, and we want to avoid changes to the base if possible so existing implementations are not invalidated. "Yellow Pages" status would be better than nothing, but quite dissapointing. I think it's a feature that should be widely available and much used. It seems hard to come up with definitive answers to some of these questions. However, I don't see any indication that the issues here are deep, so we should be able to agree on something satisfactory without a whole lot of research. So let's try to do it in time for the July (?) meeting. Chris  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 20 Apr 87 11:48:20 EDT Received: from relay2.cs.net by RELAY.CS.NET id aa10812; 20 Apr 87 11:40 EDT Received: from ti-csl by RELAY.CS.NET id ao16289; 20 Apr 87 11:32 AST Received: from Nero (nero.ARPA) by tilde id AA08324; Mon, 20 Apr 87 10:30:10 cdt To: Jonathan A Rees Cc: RRRS-Authors@MC.LCS.MIT.EDU From: David Bartley Subject: Re: meeting dates/times Date: 20-Apr-87 10:29:18 Sender: BARTLEY%Nero%ti-csl.csnet@RELAY.CS.NET Message-Id: I'm pretty open to meeting at either end of the week. I hope to attend the SIGPLAN meeting in St. Paul June 24-26, though, so meeting Saturday won't work out for me. Although I hesitate to travel on the 4 July weekend, the Thursday-Friday choice may be best. (I may just plan to stay in Boston over the weekend!) --db--  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 16 Apr 87 19:20:35 EDT Date: Thu, 16 Apr 87 19:19:38 EDT From: Jonathan A Rees Subject: meeting dates/times To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <186340.870416.JAR@AI.AI.MIT.EDU> I have heard from very few of you. Please let me know if you are planning to attend and whether you have any conflicts. Two different possibilities are being considered: A. Saturday - Sunday, 27-28 June. B. Thursday - Friday, 2-3 July. So far, the only person who has reported a definite conflict is Dan Friedman, who absolutely can't make it before July 1. Other data: - Mitch Wand would prefer not to meet on Saturday. - Kent Pitman would prefer not to meet Monday-Friday, but does not have a definite conflict. - Friday the 3rd might be difficult for Norman Adams due to approach of 4th of July. - Kent Pitman and Bill Rozas have suggested that the approach of the 4th might present problems for some people; I would encourage such people to speak up now. I am inclined now to suggest that we meet Thursday-Friday so that we can accomodate Mitch and Dan. Please reply with your preferences if you have not done so already. If you are mute you will be ignored. Jonathan  Received: from iucs.cs.indiana.edu (TCP 30003147315) by MC.LCS.MIT.EDU 16 Apr 87 16:21:57 EDT Date: Thu, 16 Apr 87 15:16:57 est From: Chris Haynes To: JAR@AI.AI.MIT.EDU Cc: rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees's message of Wed, 15 Apr 87 12:41:00 EDT <185067.870415.JAR@AI.AI.MIT.EDU> Subject: Pattern matching, not optional arguments Date: Wed, 15 Apr 87 12:41:00 EDT From: Jonathan A Rees Phil Wadler recently complained in SIGPLAN that Scheme has no built-in pattern matching like ML and its affiliates do. I think there may be something to what he says. Yes indeed. Phil's article was one of my motivations to push for pattern matching (the other was what I saw happening to lambda). Some of the ways in which Phil finds Miranda superior to Scheme I disagree with, feeling they are simply different; for example quote. I'd like to see strong type checking widely used in Scheme, but that is a very difficult matter. The one respect in which I feel Miranda is clearly superior, and that we can address with relatively little effort, is pattern matching. Yours treats lists and vectors asymmetrically, and doesn't allow for additional constructors without redefining the macro. You should consider going even closer to ML, which you could do by changing the last two alternatives to be | (list ...) | (list* ... ) Did you mean | (list* . ) ? (In ML you'd write ,,... instead of (list ...), and :: instead of (cons ).) So let's also add | (cons ), which is the same as | (list* . ). This eliminates the reserved word problem; it is possible to take a list apart and name its car VECTOR, and it is possible to make MATCH understand new kinds of constructors without causing old code to break due to name conflicts. Another way to eliminate the reserved word VECTOR would be to replace the vector line with | #( ...) This is consistant with the rest of the approach I took, which is to have patterns match the print syntax, rather than the construction expression syntax, as you would have it. (I recall originally wishing I could use the vector syntax above, but being forced to the VECTOR keyword syntax because I was working in Scheme84 at the time and it does not support the standard vector notation. Sorry I neglected to correct this damage before making the proposal public.) The use of construction pattern syntax certainly is an alternative worth consideration. It also has the big advantage that quote becomes completely consistent with the pattern style; e.g. (list 'x var) is more natural than ('x var). The ability to add new constructors in a smooth way if constructor syntax is used is potentially a big win. But to do it right (something like the clarification of your proposal below) complicates the match mechanism substantially. It also makes it clunkier to use when only lists and vectors are involved, which I expect will be the vast majority of the time. It's much like the difference between making things with list and cons vs. using quasiquote. (Actually, quasiquote might be used to make constructor syntax patterns. Argh!) If matching is to be much used for such things as optional arguments (where only lists are involved), the simplicity of the print syntax is a real plus. It's a hard choice. In fact, if you changed (? ) to ((? ) ) then you could change the syntax to be simply ::= | | | (quote ) | ( ...) Then what would be the meaning of the second and subsequent subpatterns in a pattern of the form ((? ) ...)? The predicate should see an arbitrary value that can then be destructured with a single pattern. This would permit you to say things like (let ((widget list)) ... (match w ((widget wrench connector) ...))) to take a widget (implemented as a list) apart into its wrench and connector components, and we have taken another step closer to being like ML. Giving a semantics for this in Scheme is harder than in ML since Scheme is a dynamically-typed language with only one namespace, and ML is statically typed and has four namespaces. The feat can be accomplished by making MATCH expand into a call to some procedure, call it MATCH-INTERNAL: (match x ((exp pat ...) body ...) clause ...) ==> (let ((z x)) (match-internal exp number-of-pats-following-exp z (lambda (val ...) (match val ...) ...) (lambda () (match z clause ...)))) The (lambda (val ...) ...) success continuation above doesn't quite work. The the success continuation should be passed a fail continuations (the same as the one passed to match-internal), and body ... should be within the scope of the pattern variables in each of the subpatterns. Match can also be implemented by expanding the tests inline, which results in considerable code expansion and slower compilation, but runs faster. We've used both approaches at Indiana. To provide for user defined constructors, some mechanism is needed for associating a predicate and destructuring function with each constructor. This could be done in several ways, such as a global (hash?)table or using constructor objects that responded to messages asking for their associated predicate and destructuring functions. If constructors are regularly created in dynamic ways, the global table presents garbage collection problems. But let's not get carried away with implementation concerns at this stage. In any event, I suggest that the destructuring functions take two arguments: a function to receive the component values and the value to be destructured. Thus APPLY would be the list destructuring function. (lambda (f v) (apply f (vector->list v))) could be used for vectors, but some implementations might provide a more efficient version that didn't cons up a list. If match is to support user supplied constructors, we had better be convinced that they will be regularly used and that it is important for them to be abstract. If abstraction isn't critical, one can always use lists or vectors that begin with certain flags to distinguish objects created by new constructors. For example, using this old trick the widget constructor might be (define widget (lambda (wrench connector) (list 'widget wrench connector))) A widget pattern (in print syntax) would then be ('widget wrench connector) and no widget destructuring function is needed. Our biggest use of match so far has been doing this sort of thing to represent abstract syntax. By the way, if numbers and strings can be patterns, then booleans and characters ought to be patterns too. Yes. This oversight was also a throwback to the original Scheme84 implementation of match. Jonathan Chris  Received: from iucs.cs.indiana.edu (TCP 30003147315) by MC.LCS.MIT.EDU 16 Apr 87 16:21:57 EDT Date: Thu, 16 Apr 87 15:16:57 est From: Chris Haynes To: JAR@AI.AI.MIT.EDU Cc: rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees's message of Wed, 15 Apr 87 12:41:00 EDT <185067.870415.JAR@AI.AI.MIT.EDU> Subject: Pattern matching, not optional arguments Date: Wed, 15 Apr 87 12:41:00 EDT From: Jonathan A Rees Phil Wadler recently complained in SIGPLAN that Scheme has no built-in pattern matching like ML and its affiliates do. I think there may be something to what he says. Yes indeed. Phil's article was one of my motivations to push for pattern matching (the other was what I saw happening to lambda). Some of the ways in which Phil finds Miranda superior to Scheme I disagree with, feeling they are simply different; for example quote. I'd like to see strong type checking widely used in Scheme, but that is a very difficult matter. The one respect in which I feel Miranda is clearly superior, and that we can address with relatively little effort, is pattern matching. Yours treats lists and vectors asymmetrically, and doesn't allow for additional constructors without redefining the macro. You should consider going even closer to ML, which you could do by changing the last two alternatives to be | (list ...) | (list* ... ) Did you mean | (list* . ) ? (In ML you'd write ,,... instead of (list ...), and :: instead of (cons ).) So let's also add | (cons ), which is the same as | (list* . ). This eliminates the reserved word problem; it is possible to take a list apart and name its car VECTOR, and it is possible to make MATCH understand new kinds of constructors without causing old code to break due to name conflicts. Another way to eliminate the reserved word VECTOR would be to replace the vector line with | #( ...) This is consistant with the rest of the approach I took, which is to have patterns match the print syntax, rather than the construction expression syntax, as you would have it. (I recall originally wishing I could use the vector syntax above, but being forced to the VECTOR keyword syntax because I was working in Scheme84 at the time and it does not support the standard vector notation. Sorry I neglected to correct this damage before making the proposal public.) The use of construction pattern syntax certainly is an alternative worth consideration. It also has the big advantage that quote becomes completely consistent with the pattern style; e.g. (list 'x var) is more natural than ('x var). The ability to add new constructors in a smooth way if constructor syntax is used is potentially a big win. But to do it right (something like the clarification of your proposal below) complicates the match mechanism substantially. It also makes it clunkier to use when only lists and vectors are involved, which I expect will be the vast majority of the time. It's much like the difference between making things with list and cons vs. using quasiquote. (Actually, quasiquote might be used to make constructor syntax patterns. Argh!) If matching is to be much used for such things as optional arguments (where only lists are involved), the simplicity of the print syntax is a real plus. It's a hard choice. In fact, if you changed (? ) to ((? ) ) then you could change the syntax to be simply ::= | | | (quote ) | ( ...) Then what would be the meaning of the second and subsequent subpatterns in a pattern of the form ((? ) ...)? The predicate should see an arbitrary value that can then be destructured with a single pattern. This would permit you to say things like (let ((widget list)) ... (match w ((widget wrench connector) ...))) to take a widget (implemented as a list) apart into its wrench and connector components, and we have taken another step closer to being like ML. Giving a semantics for this in Scheme is harder than in ML since Scheme is a dynamically-typed language with only one namespace, and ML is statically typed and has four namespaces. The feat can be accomplished by making MATCH expand into a call to some procedure, call it MATCH-INTERNAL: (match x ((exp pat ...) body ...) clause ...) ==> (let ((z x)) (match-internal exp number-of-pats-following-exp z (lambda (val ...) (match val ...) ...) (lambda () (match z clause ...)))) The (lambda (val ...) ...) success continuation above doesn't quite work. The the success continuation should be passed a fail continuations (the same as the one passed to match-internal), and body ... should be within the scope of the pattern variables in each of the subpatterns. Match can also be implemented by expanding the tests inline, which results in considerable code expansion and slower compilation, but runs faster. We've used both approaches at Indiana. To provide for user defined constructors, some mechanism is needed for associating a predicate and destructuring function with each constructor. This could be done in several ways, such as a global (hash?)table or using constructor objects that responded to messages asking for their associated predicate and destructuring functions. If constructors are regularly created in dynamic ways, the global table presents garbage collection problems. But let's not get carried away with implementation concerns at this stage. In any event, I suggest that the destructuring functions take two arguments: a function to receive the component values and the value to be destructured. Thus APPLY would be the list destructuring function. (lambda (f v) (apply f (vector->list v))) could be used for vectors, but some implementations might provide a more efficient version that didn't cons up a list. If match is to support user supplied constructors, we had better be convinced that they will be regularly used and that it is important for them to be abstract. If abstraction isn't critical, one can always use lists or vectors that begin with certain flags to distinguish objects created by new constructors. For example, using this old trick the widget constructor might be (define widget (lambda (wrench connector) (list 'widget wrench connector))) A widget pattern (in print syntax) would then be ('widget wrench connector) and no widget destructuring function is needed. Our biggest use of match so far has been doing this sort of thing to represent abstract syntax. By the way, if numbers and strings can be patterns, then booleans and characters ought to be patterns too. Yes. This oversight was also a throwback to the original Scheme84 implementation of match. Jonathan Chris  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 15 Apr 87 12:42:26 EDT Date: Wed, 15 Apr 87 12:41:00 EDT From: Jonathan A Rees Subject: Pattern matching, not optional arguments To: cth@IUCS.CS.INDIANA.EDU cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Mon 13 Apr 87 15:19:27 est from Chris Haynes Message-ID: <185067.870415.JAR@AI.AI.MIT.EDU> Date: Mon, 13 Apr 87 15:19:27 est From: Chris Haynes ::= | | | (quote ) | (vector ...) | (? ) | ( ...) | ( ... . ) Phil Wadler recently complained in SIGPLAN that Scheme has no built-in pattern matching like ML and its affiliates do. I think there may be something to what he says. Matching of the ML variety happens a fair amount in informal notations (e.g. mathematics, denotational semantics). What you suggest is almost the same as ML's matching facility, but not quite as elegant. Yours treats lists and vectors asymmetrically, and doesn't allow for additional constructors without redefining the macro. You should consider going even closer to ML, which you could do by changing the last two alternatives to be | (list ...) | (list* ... ) (In ML you'd write ,,... instead of (list ...), and :: instead of (cons ).) This eliminates the reserved word problem; it is possible to take a list apart and name its car VECTOR, and it is possible to make MATCH understand new kinds of constructors without causing old code to break due to name conflicts. In fact, if you changed (? ) to ((? ) ) then you could change the syntax to be simply ::= | | | (quote ) | ( ...) This would permit you to say things like (let ((widget list)) ... (match w ((widget wrench connector) ...))) to take a widget (implemented as a list) apart into its wrench and connector components, and we have taken another step closer to being like ML. Giving a semantics for this in Scheme is harder than in ML since Scheme is a dynamically-typed language with only one namespace, and ML is statically typed and has four namespaces. The feat can be accomplished by making MATCH expand into a call to some procedure, call it MATCH-INTERNAL: (match x ((exp pat ...) body ...) clause ...) ==> (let ((z x)) (match-internal exp number-of-pats-following-exp z (lambda (val ...) (match val ...) ...) (lambda () (match z clause ...)))) I.e. MATCH-INTERNAL takes the constructor, the number of arguments to the constructor (i.e. subpatterns), the thing to be matched, and success and failure continuations. MATCH-INTERNAL then dispatches on the constructor: (define (match-internal constructor nargs obj succeed fail) (cond ((eq? constructor list) (if (and (list? obj) (= (length obj) nargs)) (apply succeed obj) (fail))) ((eq? constructor list*) ...) ((eq? constructor vector) ...) ((?-constructor? constructor) (if (and (= nargs 1) ((?-predicate constructor) obj)) (succeed obj) (fail))) ... (else (error "unknown constructor" ...)))) (define (? pred) ...something which answers true to the ?-constructor? predicate ...) This the same kind of mechanism as is used for T's equivalent of Common Lisp's SETF. Like T's SETF, it could be made user-extensible, and it could be made efficiently compilable. If it expanded macro forms, then it could also handle QUASIQUOTE with no extra work (as long as the expansion conatained only constructors that MATCH-INTERNAL knew about). By the way, if numbers and strings can be patterns, then booleans and characters ought to be patterns too. Jonathan  Received: from iuvax.cs.indiana.edu (TCP 30003147300) by MC.LCS.MIT.EDU 14 Apr 87 02:34:44 EDT Date: Tue, 14 Apr 87 01:31:05 est From: Dan Friedman Received: by iuvax.cs.indiana.edu; id AA06378; Tue, 14 Apr 87 01:31:05 est To: rrrs-authors@mc.lcs.mit.edu Subject: meeting dates These letters/dates appeared to have arrived but apparently they did not. /* Written 12:20 am Mar 30, 1987 by dfried@iuvax.cs.indiana.edu in iuvax:scheme-rrrs */ /* ---------- "meeting" ---------- */ From: Dan Friedman I agree with Will about getting together. Any time before July 1st will be very difficult for me Dan /* End of text from iuvax:scheme-rrrs */ /* Written 8:48 am Apr 10, 1987 by dfried@iuvax.cs.indiana.edu in iuvax:scheme-rrrs */ /* ---------- "travel plans" ---------- */ From: Dan Friedman I need to know the date/dates that we will be meeting asap. Dan /* End of text from iuvax:scheme-rrrs */ /* Written 10:22 am Apr 11, 1987 by dfried@iuvax.cs.indiana.edu in iuvax:scheme-rrrs */ /* ---------- "date of meeting" ---------- */ From: Dan Friedman I am unable to make a meeting until July. The first weekend in July would be fine with me. Dan /* End of text from iuvax:scheme-rrrs */ ----- Dan  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 13 Apr 87 23:50:22 EDT Date: Mon, 13 Apr 87 23:49:15 EDT From: Jonathan A Rees Subject: towards an agenda - yeller pages To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <184057.870413.JAR@AI.AI.MIT.EDU> [Seems that CSNET had amnesia this weekend, so I'm re-sending this message. - Jonathan] Date: Sat, 11 Apr 87 11:15:02 EDT From: Jonathan A Rees Subject: towards an agenda - yeller pages To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Wed 8 Apr 87 15:39:02 cdt from David Bartley Message-ID: <183040.870411.JAR@AI.AI.MIT.EDU> I nominate the general topic of "yellow pages" for the agenda, with the following subtopics: - what the yellow pages are for - string manipulation - bitwise logical operators - byte vectors (or something a little more general) - hash tables - I/O extensions (e.g. READ-LINE, READ-STRING, maybe a simple FORMAT) - sets ? - arrays ? Some thoughts: By yellow pages I mean a collection of facilities that are implementable (although not necessarily implemented) in terms of things that are already in the language. A description of a yellow pages facility should be accompanied by a sample implementation for two reasons: (1) as a substitute for a formal specification (which are hard to write); (2) as an existence proof that the facility is implementable. The informal description should specify what behavior of the sample implementation is accidental and what's not (e.g. (PAIR? a-hash-table) might be true in a sample implementation, but not part of the spec). If we can figure out modules (packages, whatever) then we might even be able to get away with keeping these things out of the global namespace. If we have an official notion of yellow-page, then we should be able to demote some of the things that are currently in the main part of the report (MEMQ, EQUAL?, VECTOR-FILL!). In addition, if we can agree on macros, most of the derived expression types (with the possible exception of BEGIN and LETREC) can be similary demoted. I don't think I like the term "yellow page", but that's another story. - Jonathan  Received: from iucs.cs.indiana.edu (TCP 30003147315) by MC.LCS.MIT.EDU 13 Apr 87 16:23:55 EDT Date: Mon, 13 Apr 87 15:19:27 est From: Chris Haynes To: rrrs-authors@mc.lcs.mit.edu Subject: Pattern matching, not optional arguments RPG: If the strategy is to be able to pass an arbitrary number of arguments, then a syntax that binds one variable to all of them following by a pretty destructuring bind of some sort is much better than a syntax that mixes required with &rest (as Jonathan suggested). JAR: I agree. In my experience, pattern-matching languages seem to have an inevitable tendency to become baroque and disgusting. But let's not stop looking for a decent one. Me too. Our experience at Indiana is that a relatively simple match facility goes a long long way. It does not need to complicate the rest of the language. On the contrary, I think it eliminates any justification for making lambda baroque and disgusting. Please, let's make an honest attempt to standardize on a matching facility first, and only then decide if their is sufficient justification to corrupt the jewel of Scheme. Given match, we may even be able to polish our jewel by relegating the "." rest feature to optional or discarded status. To fuel the debate, which I hope will have matured by the time of our next meeting, here is documentation for a match facility that I've enjoyed using. ----------------------------- (match ( ...) ...) ::= | | | (quote ) | (vector ...) | (? ) | ( ...) | ( ... . ) Match is a fairly general pattern matching and destructuring facility. is evaluated and its value is matched against the s in order until a matching pattern is found. An error is signaled if no pattern matches. When a match is found, the value of is destructured with the variables in the matching pattern bound to the corresponding components of 's value. The expressions of the matching pair are then evaluated in an environment formed by extending the environment of the match expression with these new bindings. The value of the last expression is returned as the value of the match expression. The symbols QUOTE, VECTOR and ? are reserved in patterns to identify literals, vectors and predicate tests. Numbers, strings and quoted literal s must be EQUAL? to corresponding components of s value, or the pattern fails. expressions should evaluate to unary functions that are applied to the corresponding component of s value when matching of the ? pattern is attempted. If the predicate returns false, the pattern fails. Otherwise, the value applied to the predicate is matched against the pattern following the predicate. (match '(2 . 3) ((a . b) (* a b))) ==> 6 (match '(1 2) ((a) a) ((a b) (+ a b)) (c c)) ==> 3 (match (list 33 "string" (vector 1 2)) ((33 "string" (vector a b)) (cons a b))) ==> (1 . 2) (let ((num 3)) (match (cons 'x 4) (((? (lambda (v) (or (symbol? v) (and (number? v) (= v num)))) c) . (? number? d)) (list c d)))) ==> (x 4) (match '(bar 3 4 5) (('foo x y) (cons x y)) (('bar x y . z) (list x y z)) (else (error "didn't match: " else))) ==> (3 4 5) ----------------------------- The most questionable feature of this proposal is the predicate mechanism. I like it, but some others here don't. I'd like to have others opinions, and would not mind if this feature were dropped. A more significant issue is how to distinguish literal symbols from pattern variables. Scheme84 currently had an experimental match facility that is similar to that above, but without a predicate mechanism, with an optional else clause (rather than the ELSE variable hack used above), and with a required list of pattern variables that eliminated the need for literal quoting. For example, in the current version of Scheme84 the last example above would have required the pattern variable list (x y z): (match '(bar 3 4 . 5) (x y z) ((foo x y) (cons x y)) ((bar x y . z) (list x y z)) (else (error "No match"))) ==> (3 4 5) We found that remembering to update the list of pattern variables when patterns were changed is a nuisance. Also, the quote mechanism seems more natural, simpler and more expressive than the pattern variable list, so we no longer favor the pattern list approach. I'd be quite happy if there were no other matching or destructuring facility. In the absense of a multiple value mechanism, I'd favor a destructuring option for LET, e.g. (let (((x y) (cons 1 2))) ...); however multiple values eliminates much of the need for this. If I were writing a system in which many functions had optional arguments, I would want to write a macro like Jonathan's OPTIONALS, but that could be done easily with match. In other situations I might want (match-lambda pairs ...) ==> (lambda args (match args pairs ...))) or versions of lambda and let that destructured, but this sort of thing probably doesn't belong in the standard. -- Chris Haynes Dan  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 13 Apr 87 00:26:48 EDT Received: from relay2.cs.net by RELAY.CS.NET id af12757; 13 Apr 87 0:20 EDT Received: from northeastern.edu by RELAY.CS.NET id ag20908; 13 Apr 87 0:17 AST Received: from corwin.ccs.northeastern.edu by nuhub.acs.northeastern.edu; Sun, 12 Apr 87 23:46 EST Received: by corwin.CCS.Northeastern.EDU (5.51/5.17) id AA08253; Sun, 12 Apr 87 22:36:39 AST Date: Sun, 12 Apr 87 22:36:39 AST From: wand%corwin.ccs.northeastern.edu@RELAY.CS.NET To: JAR@MC.LCS.MIT.EDU, rrrs-authors@MC.LCS.MIT.EDU Subject: Re: meeting dates/times/places I would prefer not meeting on Saturday, if it is at all possible --Mitch  Received: from hplabs.HP.COM (TCP 30001235012) by MC.LCS.MIT.EDU 12 Apr 87 20:24:38 EDT Received: from hplms1 by hplabs.HP.COM with TCP ; Sun, 12 Apr 87 16:20:01 pst Received: from hplwhh (hplwhh) by hplms1; Sun, 12 Apr 87 16:19:39 pst Return-Path: Received: by hplwhh ; Sun, 12 Apr 87 17:19:23 pdt From: Warren Harris Message-Id: <8704130019.AA04702@hplwhh> To: jinx@geneva.ai.mit.edu, bartley%home%ti-csl.csnet@relay.cs.net Cc: rrrs-authors@mc.lcs.mit.edu X-Mailer: mh Subject: Re: number syntax In-Reply-To: Your message of 10 Apr 87 16:18:11 PDT (Fri). <8704102318.AA07578@tekchips.TEK.COM> Date: Sun, 12 Apr 87 16:19:17 PST > ... the original proposal is such that both exact and inexact > flonums are possible (and desirable), and similarly for the other > types. Although we have not implemented it, we have an implementation > in mind, and it is orthogonal: for each type of number, there is a bit > specifying whether it is exact or not. In the presence of an exactness indicator bit, I would be all for adding an exactness indicator to number syntax. This would allow the user to explicitly specify whether a number is exact or inexact, independent of its type. For example, one could use: -3.14, 7/8, 2+7i, to mean an exact quantities, and: ~-3.14, ~7/8, ~2+7i to mean inexact quantities. (I use tilde to indicate "approximately" as opposed to "not" like in C). This explicit notation would allow exactness to be preserved by coersion operators: (float ~7/2) => ~3.5 as well as removing ambiguities from operations such as: (sqrt 4) => 2 (sqrt ~4) => ~2 (sqrt 4.0) => 2.0 ; this would have been considered inexact ; if all flonums were inexact (sqrt 3) => ~1.7320508075688772 ; finite precision (sqrt -4) => 0+2i ; this might have been considered inexact too  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 11 Apr 87 11:16:22 EDT Date: Sat, 11 Apr 87 11:15:02 EDT From: Jonathan A Rees Subject: towards an agenda - yeller pages To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Wed 8 Apr 87 15:39:02 cdt from David Bartley Message-ID: <183040.870411.JAR@AI.AI.MIT.EDU> I nominate the general topic of "yellow pages" for the agenda, with the following subtopics: - what the yellow pages are for - string manipulation - bitwise logical operators - byte vectors (or something a little more general) - hash tables - I/O extensions (e.g. READ-LINE, READ-STRING, maybe a simple FORMAT) - sets ? - arrays ? Some thoughts: By yellow pages I mean a collection of facilities that are implementable (although not necessarily implemented) in terms of things that are already in the language. A description of a yellow pages facility should be accompanied by a sample implementation for two reasons: (1) as a substitute for a formal specification (which are hard to write); (2) as an existence proof that the facility is implementable. The informal description should specify what behavior of the sample implementation is accidental and what's not (e.g. (PAIR? a-hash-table) might be true in a sample implementation, but not part of the spec). If we can figure out modules (packages, whatever) then we might even be able to get away with keeping these things out of the global namespace. If we have an official notion of yellow-page, then we should be able to demote some of the things that are currently in the main part of the report (MEMQ, EQUAL?, VECTOR-FILL!). In addition, if we can agree on macros, most of the derived expression types (with the possible exception of BEGIN and LETREC) can be similary demoted. I don't think I like the term "yellow page", but that's another story. - Jonathan  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 10 Apr 87 23:56:13 EDT Received: from relay2.cs.net by RELAY.CS.NET id aa19043; 10 Apr 87 23:48 EDT Received: from tektronix.tek.com by RELAY.CS.NET id ae09755; 10 Apr 87 23:41 AST Received: by tektronix.TEK.COM (5.51/6.20) id AA21241; Fri, 10 Apr 87 16:19:49 PDT Received: by tekchips.TEK.COM (5.31/6.19) id AA07578; Fri, 10 Apr 87 16:18:13 PDT Message-Id: <8704102318.AA07578@tekchips.TEK.COM> To: rrrs-authors@MC.LCS.MIT.EDU Cc: bartley%home%ti-csl.csnet@RELAY.CS.NET, willc%tekchips.tek.com@RELAY.CS.NET, jinx%geneva.ai.mit.edu@RELAY.CS.NET Subject: Re: number syntax In-Reply-To: Your message of Thu, 9 Apr 87 19:11:01 est. <8704100011.AA22486@geneva> Date: 10 Apr 87 16:18:11 PDT (Fri) From: willc%tekchips.tek.com@RELAY.CS.NET Bartley: Has anyone implemented exactness using a mechanism substantially different from the one Kent Dybvig describes in his new book? (Quoting his page 111: "In practice, the internal representation for an exact quantity is as an integer or ratio, and the internal representation for an inexact quantity is as a floating point number, although other representations are possible." Also, "The exactness of a complex numeric object depends on the exactness of its real and imaginary parts.") How do people feel about this approach? Does this fulfill the spirit of exactness? Does anyone want to pay for a more orthogonal exactness attribute for numbers? The passage quoted says "integer" and "ratio" and "floating point number" when the proper R3RS terminology is "fixnum or bignum" and "ratnum" and "flonum". I feel like I'm being overly picky by pointing this out, since all of these terms (except integer) are implementation-dependent and the book describes only Chez Scheme, but Jinx's response shows why precision is important in words as well as numbers. Jinx: That is very much against the proposal. We have not implemented it at MIT, but the original proposal is such that both exact and inexact flonums are possible (and desirable), and similarly for the other types. Although we have not implemented it, we have an implementation in mind, and it is orthogonal: for each type of number, there is a bit specifying whether it is exact or not. I have to disagree with Jinx's first two sentences above. R3RS makes clear that exact reals and inexact integers are both possible and desirable, but it says nothing at all about exact flonums and inexact fixnums. Though their semantics are poorly defined in R3RS, "exact" and "inexact" are intended to be significant concepts in the language. By contrast, "flonum" and "fixnum" are names for internal representation strategies that have no standing in the language. Thus "exact flonum" is at best an implementation concept, and at worst a category error. Suppose I implement Scheme (without complex numbers, to keep things simpler) by representing all numbers as ratnums, augmented by a bit that tells whether the number is exact or inexact. This is perfectly legitimate, right? Now suppose people complain about its performance on certain numerical programs, and my investigations show that the reason for the poor performance is that it takes too long to add and to multiply inexact reals. Suppose I tweak my implementation by arranging for inexact reals to be represented as flonums, augmented by a bit that tells whether the number is exact or inexact. That's a perfectly legitimate efficiency hack, right? Suppose I then notice that the exactness bit for a real represented as a flonum always says that the real is inexact, because I'm still representing exact reals as ratnums. So I flush the exactness bit for reals represented as flonums, because the fact that the real is represented as a flonum implies that it's inexact. I would be silly not to, right? If I then add two more efficiency hacks by representing exact integers as bignums, and by representing small exact integers as fixnums, I arrive at an implementation similar to that hinted at by Dybvig's book. Not only do I see nothing wrong with this, it seems the obvious way to go. In terms of Jinx's remarks, you can be orthogonal at the language level without being orthogonal at the implementation level. I would oppose any attempt to mandate particular implementation strategies. Cadence Research and TI and Tektronix have no more right to impose their favorite implementation strategy on MIT than MIT has to impose its favorite strategy on us. Bartley: Is it permissible for an exact 3.5 to print (by default) as 7/2 or an inexact 2 to print as 2.0? Fine with me. I'm more concerned about whether "7/2" reads as an exact 3.5 and whether "2.0" reads as an inexact 2. The examples in section 6.8 of R3RS are sufficient to imply that "1" and "5" read as exact integers, assuming that the same reader is used to read both programs and data. Peace, Will  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 10 Apr 87 19:37:25 EDT Received: from relay2.cs.net by RELAY.CS.NET id ae15584; 10 Apr 87 19:22 EDT Received: from ti-csl by RELAY.CS.NET id al08455; 10 Apr 87 19:19 AST Received: from home (home.ARPA) by tilde id AA05738; Fri, 10 Apr 87 17:15:01 cdt Received: by home id AA13566; Fri, 10 Apr 87 17:13:35 cdt Date: Fri, 10 Apr 87 17:13:35 cdt From: David Bartley Message-Id: <8704102213.AA13566@home> To: jinx%geneva.ai.mit.edu@RELAY.CS.NET Cc: bartley%home%ti-csl.csnet@RELAY.CS.NET, rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: "Guillermo J. Rozas"'s message of Thu, 9 Apr 87 19:11:01 est Subject: number syntax > [Bartley:] > Is it permissible for an exact 3.5 to print (by default) as 7/2 or an > inexact 2 to print as 2.0? > > [Jinx:] > It depends on the format specification. For the explicit ones, there > should be no question. I think, however, that if the format is (HEUR) > it should print as #i2 . I agree that an inexact integer 2 >should< print as #i2, but is it permissible to print it as 2.0? Likewise, is it permissible for the reader to read 2.0 as an inexact integer 2? May it read #e3.5 as the rational number 7/2 rather than an "exact" float (whatever that may be)? What I'm leading to is that any discussion about how to represent numbers that are read in without benefit of an explicit exactness indicator will have to deal with the issue of alternative ways to represent exactness. BTW--How do those that believe in keeping exactness orthogonal to numeric subtype plan to deal with "exact" reals that are not rational? --db--  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 10 Apr 87 19:18:21 EDT Date: Fri, 10 Apr 87 19:17:09 EDT From: Jonathan A Rees Subject: meeting dates/times/places To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <182720.870410.JAR@AI.AI.MIT.EDU> KMP's suggestion that we meet over the weekend of 27-28 June was seconded by Jinx and assented to by Will. The weekend is fine with me too. I don't think it will be difficult to find a reasonable room in which to meet on a weekend, but I'll officially arrange for a room if possible. Getting into Tech Square is no problem; the lobby doors on each floor will be locked, but we can probably work something out (doorbell, a room near a door, or a room somewhere else on the MIT campus). If I hear no objections to 27-28 within the next couple weeks, I'll start looking into this more seriously. Then we can start thinking about what time of day we want to start on Saturday and Sunday. ****** Let me know if think you might attend so I can determine the optimal ****** room size. KMP et al. -- is Monday morning a possibilty? If so we could consider meeting Sunday all day and Monday morning. What time of day will the X3J13 subcommittees start meeting? Jonathan.  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 10 Apr 87 18:48:42 EDT Date: Fri, 10 Apr 87 18:46:55 EDT From: Jonathan A Rees Subject: macros To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: RRRS-Authors@MC.LCS.MIT.EDU In-reply-to: Msg of Fri 10 Apr 87 10:26:31 cdt from David Bartley Message-ID: <182704.870410.JAR@AI.AI.MIT.EDU> Date: Fri, 10 Apr 87 10:26:31 cdt From: David Bartley -- One or two namespaces or a hybrid? I think this could coherently go either way. T switched from one namespace to two after a year or so in order to be compatible with MIT Scheme. I'll flame about this later if need be. How do we deal with the fact that both macro/syntax keywords and variables are drawn from the same set of identifiers? I think lambda-bound names should take precedence over keywords, but should LET-SYNTAX-bound keywords take precedence over lambda-bound names of an outer level? For symmetry, the answer must be yes. What about top-level DEFINE? Does (DEFINE X ...), like (LAMBDA (X) ...), take precedence over keywords? A harder question. The definition could be an error if X has a keyword binding in that lexical contour. What do we do with keywords that appear in places where a keyword is not expected, like (+ IF AND), and thus appear to be variable references? Error. Should we embed syntax tables in the lexical environment or keep them separate? This is practically the same as the one versus two namespace question. I don't know what distinction you're trying to make here. For those who might prefer a single namespace: should INLINE and other optimizations be encompassed? How about named constants like PI and EOF-OBJECT? No. No. -- Mutable or immutable syntax tables? Immutable. Otherwise you get all sorts of obscure bugs and disgusting semantic questions. The semantic questions remain if an STF (i.e. expander) can detect or produce side-effects, but every little bit of sanity helps. It seems excessively cumbersome to wrap a LET-SYNTAX around a file or collection of files. Immutable does not imply LET-SYNTAX. A DEFINE-MACRO-esque for could work just as well. Simply make DEFINE-MACRO part of the syntax of a (or perhaps even a . The scope of the macro then starts at the point the DEFINE-MACRO occurs, and ends at the end of the file, , or . Why should extending the syntax differ from the style of incrementally adding definitions with DEFINE? Maybe it shouldn't. The main difference is that DEFINE's can be mutually recursive, whereas you run into all sorts of nasty problems if you try to make the scope a macro definition include any text that precedes it. (This is because you have to expand macros in order to determine whether or not a macro definition is present in the first place.) Perhaps INCLUDE is a better answer than LOAD. Perhaps. This seems like an independent question, however, more properly discussed under the heading of "modules". -- Solution of capture problems Eugene and others have addressed this. What is the computational complexity of the hygienic expansion algorithm, by the way? -- Must a macro expand into an expression--i.e. not a keyword? Yes. -- Which syntax table is used by various REPLs, LOAD, COMPILE-FILE, etc.? The report doesn't talk about REPL's. The syntax table for files should be the standard one (i.e. the one with only the official bindings in it, no user bindings). If the file wants to use nonstandard syntax it must explicitly request them using a DEFINE-MACRO or USE-SYNTAX-TABLE form which is effective only for that file. For controlling the REPL's syntax table, you could have something like (set-current-syntax-table ...). This should have no effect on which macros are seen by LOAD, however. -- What about macros that expand into multiple definitions? No problem: the expansion can be (begin (define ...) (define ...)). BEGIN behaves like Maclisp's (PROGN 'COMPILE ...). -- Should a macro writer have the ability to make absolute (that is, "qualified") references? I don't see what the alternative is. Otherwise there's no way to write things like QUASIQUOTE. -- Should COMPILE-FILE execute any of the forms it compiles? Yes, the right-hand side of a DEFINE-MACRO or USE-SYNTAX-TABLE, and the body of an (AT-PREPROCESS-TIME ...). -- Can we avoid EVAL-WHEN ? Yes, but we might need something like (AT-PREPROCESS-TIME ...) in order to make definitions available to expansion procedures. * * * How much agreement must we reach to be useful? -- basic principles? Deciding how identifiers in programs are resolved as references is a good start. The R^3 report hedges this question, and we may be able to persist in this. -- a syntax for >using< macros? Necessary. There's not much point in defining a macro if you can't use it. We're probably wedded to the current syntax that can only distinguish macros from applications by recognizing keywords. This is not a problem. -- a syntax for >defining< macros? A portable way for defining "global" macros would satisfy many users and may be easier to reach agreement on than dealing more deeply with scoping issues. On the other hand, many of us will probably proceed to implement lexically scoped syntax definitions. I think scoped macros are absolutely essential. Otherwise there's absolutely no hope of writing portable code, as Jim Miller has reminded us. -- user-friendly syntax for defining macros Since user-friendly macro definition capabilities tend to have restricted capabilities, this will probably always be an extension beyond more primitive capabilities. Perhaps this is a candidate for the "yellow pages." Please define user-friendly. I certainly would hope that something that complicated could be defined as a yellow-pages layer. Obviously no one would would want to actually write macros using only the low-level primitives in my proposal. I have implemented something a bit higher level which, like EXTEND-SYNTAX, uses an input pattern, but unlike EXTEND-SYNTAX doesn't use an output pattern. But it's not obvious that everyone will like either my pattern language or Gene's, so I advocate making the lower-level hooks available as well. Next time try to come up with some challenging questions.... 8*& Jonathan  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 10 Apr 87 15:41:03 EDT Date: Fri, 10 Apr 87 15:39:27 EDT From: Chris Hanson Subject: number syntax To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Thu 9 Apr 87 16:19:28 cdt from David Bartley Message-ID: <182630.870410.CPH@AI.AI.MIT.EDU> Date: Thu, 9 Apr 87 16:19:28 cdt From: David Bartley Has anyone implemented exactness using a mechanism substantially different from the one Kent Dybvig describes in his new book? (Quoting his page 111: "In practice, the internal representation for an exact quantity is as an integer or ratio, and the internal representation for an inexact quantity is as a floating point number, although other representations are possible." Also, "The exactness of a complex numeric object depends on the exactness of its real and imaginary parts.") How do people feel about this approach? Does this fulfill the spirit of exactness? Does anyone want to pay for a more orthogonal exactness attribute for numbers? Is it permissible for an exact 3.5 to print (by default) as 7/2 or an inexact 2 to print as 2.0? We have not yet implemented exactness. Has anyone implemented the -1+2i or 5@7 syntax for complex numbers? Is there strong resistance to Common Lisp's #c(-1 2) representation? We have implemented this syntax. I don't have strong feelings about this.  Received: from Think.COM (TCP 1201000006) by MC.LCS.MIT.EDU 10 Apr 87 12:46:18 EDT Received: from godot.think.com by Think.COM; Fri, 10 Apr 87 12:42:01 EST Received: from desiderius by godot.think.com via CHAOS; Fri, 10 Apr 87 12:41:55 EST Date: Fri, 10 Apr 87 11:42 EST From: Guy Steele Subject: number syntax To: bartley%home%ti-csl.csnet@relay.cs.net, rrrs-authors@mc.lcs.mit.edu Cc: gls@think.com In-Reply-To: <8704092119.AA23970@home> Message-Id: <870410114254.2.GLS@DESIDERIUS.THINK.COM> Date: Thu, 9 Apr 87 16:19:28 cdt From: David Bartley Has anyone implemented the -1+2i or 5@7 syntax for complex numbers? Is there strong resistance to Common Lisp's #c(-1 2) representation? Actually, I think the #C(1 2) notation is really awful. It was the result of a compromise--some persons did not want to have to implement hairier token parsing for complex numbers. Much of the motivation for the notion of "potential numbers" was to leave the path open for Common Lisp eventually to adopt such a notation as -1+2i. --Guy  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 10 Apr 87 12:20:11 EDT Received: from relay2.cs.net by RELAY.CS.NET id ac03508; 10 Apr 87 12:06 EDT Received: from ti-csl by RELAY.CS.NET id ae06442; 10 Apr 87 12:02 AST Received: from home (home.ARPA) by tilde id AA04458; Fri, 10 Apr 87 09:28:07 cst Received: by home id AA06276; Fri, 10 Apr 87 10:26:31 cdt Date: Fri, 10 Apr 87 10:26:31 cdt From: David Bartley Message-Id: <8704101526.AA06276@home> To: RRRS-Authors@MC.LCS.MIT.EDU Cc: Bartley%home%ti-csl.csnet@RELAY.CS.NET Subject: macros I confess that I find the macro problem to be one of the hairiest yet one of the most important ones we face. I'm not yet ready to comment on Jonathan's proposal because it differs so much from my current approach that I need to re-examine my assumptions and biases. Before debating the specific merits of any particular proposal, perhaps we should discuss some basic issues first and work our way up from there. I'd also like to get a feel for what kind of an agreement, and how much of one, we should be working towards. My list of basic issues regarding macros includes... -- One or two namespaces or a hybrid? How do we deal with the fact that both macro/syntax keywords and variables are drawn from the same set of identifiers? I think lambda-bound names should take precedence over keywords, but should LET-SYNTAX-bound keywords take precedence over lambda-bound names of an outer level? What about top-level DEFINE? Does (DEFINE X ...), like (LAMBDA (X) ...), take precedence over keywords? What do we do with keywords that appear in places where a keyword is not expected, like (+ IF AND), and thus appear to be variable references? Should we embed syntax tables in the lexical environment or keep them separate? For those who might prefer a single namespace: should INLINE and other optimizations be encompassed? How about named constants like PI and EOF-OBJECT? -- Mutable or immutable syntax tables? It seems excessively cumbersome to wrap a LET-SYNTAX around a file or collection of files. Why should extending the syntax differ from the style of incrementally adding definitions with DEFINE? Perhaps INCLUDE is a better answer than LOAD. -- Solution of capture problems Eugene and others have addressed this. -- Must a macro expand into an expression--i.e. not a keyword? Suppose an (*IF*) macro expands into the identifier IF. Then how does one interpret the result of the expansion ((*if*) a b c) ==> (if a b c)? -- Which syntax table is used by various REPLs, LOAD, COMPILE-FILE, etc.? -- What about macros that expand into multiple definitions? -- Should a macro writer have the ability to make absolute (that is, "qualified") references? -- Should COMPILE-FILE execute any of the forms it compiles? -- Can we avoid EVAL-WHEN ? * * * How much agreement must we reach to be useful? -- basic principles? Deciding how identifiers in programs are resolved as references is a good start. -- a syntax for >using< macros? We're probably wedded to the current syntax that can only distinguish macros from applications by recognizing keywords. -- a syntax for >defining< macros? A portable way for defining "global" macros would satisfy many users and may be easier to reach agreement on than dealing more deeply with scoping issues. On the other hand, many of us will probably proceed to implement lexically scoped syntax definitions. -- user-friendly syntax for defining macros Since user-friendly macro definition capabilities tend to have restricted capabilities, this will probably always be an extension beyond more primitive capabilities. Perhaps this is a candidate for the "yellow pages." What is a reasonable goal for us to work towards? --db--  Received: from mephisto (TCP 2206400250) by MC.LCS.MIT.EDU 10 Apr 87 10:37:23 EDT Received: by MEPHISTOPHELES.AI.MIT.EDU; Fri, 10 Apr 87 10:33:31 edt Date: Fri, 10 Apr 87 10:33:31 edt From: jmiller@MEPHISTOPHELES.AI.MIT.EDU (Jim Miller) Message-Id: <8704101433.AA00738@mephisto> To: rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees's message of Thu, 9 Apr 87 21:49:15 EDT Subject: yellow pages D'Accord! I personally feel that the highest and simplest item on the agenda should be an agreement on a STANDARD way to guarantee in ALL implementations that a program written using all and only the features in R^nS will run. We discussed and rejected an attempt to work on this just before publication of the report because of time constraints. This means, essentially, some standardized way to wrap code indicating that the R^nS syntax and reader are to be used. Once we have this, we can actually begin to exchange our code with confidence that it will work as intended at the recipient's end -- which simply isn't true today without a wizard as the receiver. --Jim  Received: from grape.ads.ARPA (TCP 1200400070) by MC.LCS.MIT.EDU 10 Apr 87 02:46:39 EDT Received: by hobbes.ads.arpa (3.2/SMI-3.2) id AA10303; Thu, 9 Apr 87 23:41:40 PDT Date: Thu, 9 Apr 87 23:41:40 PDT From: andy@hobbes.ads.ARPA (Andy Cromarty) Message-Id: <8704100641.AA10303@hobbes.ads.arpa> To: JAR@AI.AI.MIT.EDU Subject: Re: readers & tokenizers Cc: andy%hobbes@ads.arpa, rrrs-authors@MC.LCS.MIT.EDU Reply-To: andy@ADS.arpa The T model, or something like it, seems to meet the criteria I proposed for statelessness. What I would prefer to see us avoid is the monolithic global model of read tables. T seems to offer one nice way to do that, given your description. I have used read-time conditionalization in the past and have concluded that it is not a good idea. If a language must have conditionalization, it must have run-time semantics.... What I always do is encapsulate implementation dependencies by defining an interface, and then write multiple implementations of the same interface. In my experience this leads to code that's much prettier, more modular, AND more portable. Why won't this work for you? In what I recall you guys at universities calling the "real world," we often don't have the luxury of writing all the code ourselves, nor even of specifying it. One specific case I had in mind when I wrote my note was a medium-sized (~25,000 lines of code) LISP software tool written in Common LISP that we have been rendering compatible with Scheme. (Note that I did not say "porting to Scheme" -- it must remain fully compatible with the other LISPs in which it executes, and given its size it is unthinkable to maintain separate versions of the source as the software is constantly extended.) Use of #+/#- reader conditionals have permitted us to add minimal annotations to this software and make it compatible with Scheme. Perhaps more importantly, the code *already* contains #+ and #-, because it is "real" code written to run under 3 brands of Common Lisp, as well as MacLISP and Franz, and we don't have the option of ripping all that stuff out (nor the budget and wo/manpower to rip all the offending conditionalization code out). The harsh reality was that being able to use existing desirable software tools required us to support #+ and #-, because historically that has been viewed as the "clean" way to conditionalize other LISP code. (Note that this is not the same as arguing, for example, that the Scheme reader should support InterLisp CLisp syntax or something along those lines. It merely recognizes that the way code has been written to make it portable is using #+ and #-, and if we want to make it possible to run non-trivial non-Scheme LISP code in Scheme, this may be the lowest-cost highest-payoff addition to Scheme's reader that we could make.) I disagree with the implication that Scheme has escaped run-time conditionalization. I made a comment about this many months ago when we discussed LOAD. If we really want to be able to view our files as containing static code, then we cannot have a LOAD of the sort we presently use, in my view; we need an INCLUDE instead, specifically one that is utterly literal in its interpretation. That is, for files as in file1: (set! *closed-var 1) (set! *closed-var 2) file2: (let ((*closed-var '())) (if (read) (include "file1")) *closed-var) then "loading" or "executing" file2 would be identical to executing (let ((*closed-var '())) (if (read) (set! *closed-var 1) (set! *closed-var 2)) *closed-var) The use of LOAD introduces some fascinating difficulties into the sort of static analysis of code you wish to perform; for example consider "loading or executing" file2, with contents as per file1: (set! foo (lambda () (write 'goodbye)(newline))) file2: (define foo (lambda () (write 'hello)(newline))) (if (read) (load "file1")) (foo) The extension to problems with macros (especially if we can redefine IF, for example -- which I advocate permitting, BTW), is equivalently problematic, or more so. The point is that we already have introduced constructs that render static analysis difficult or meaningless, even where there might have been cleaner alternatives (INCLUDE instead of LOAD, say). I would not find an argument that this is poor use of LOAD very interesting, since these (ab)uses of LOAD seem to me to be very much in the spirit of dynamic-scoping-of-the-execution-environment that was precisely the reason LOAD was defined the way it was in R3RS, at least according to my recollection of the discussion. I also would add that, although we did create additional primitives for managing a sort of "features list" in ADS Scheme, there is no need to do this if you wish to have a Scheme that supports #+scheme and yet remains susceptible to static analysis. If the user may not change the "features list," then the compiler always can know that #+scheme can be ignored and that #-scheme means "the following expression reliably will be discarded." The same static interpretation rules can hold for other #+/#- "features." I see no problems for static analysis in this case. Regards, asc  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 9 Apr 87 22:23:10 EDT Date: Thu, 9 Apr 87 22:21:24 EDT From: Jonathan A Rees Subject: readers & tokenizers To: andy@ADS.ARPA cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Thu 9 Apr 87 14:11:51 PDT from andy at hobbes.ads.ARPA (Andy Cromarty) Message-ID: <182109.870409.JAR@AI.AI.MIT.EDU> Date: Thu, 9 Apr 87 14:11:51 PDT From: andy at hobbes.ads.ARPA (Andy Cromarty) One of the difficulties with conventional read tables is that they become very dangerous in a "real" production software environment... I have no objection to an improved input system if it is stateless. ... Just for the record, I fell obliged to point out that T has a parameterized reader (i.e. readtables), and at the same time it is completely safe and stateless. There is no such thing as *READTABLE* in T; the global default reader parameters are immutable. There is a version of READ (called READ-OBJECT) which takes a read table as an argument. READ extracts a read table out of the port being read from and then calls READ-OBJECT. A port's readtable is initially the standard readtable when the port is opened, but it can be set to be something else after the port is opened; thus readtables are lexically scoped. A user can create new readtables and mutate them (e.g. define a read macro or alter the input radix), but the standard readtable is immutable, so there's no way you can accidentally step on a readtable that someone else will see. I do not propose this for Scheme, but I thought you should know that stateless doesn't mean you have to throw away the possibility of something higher level than the scanner you suggest, or even read macros. I think a function of the sort you propose would be fine, that's basically the minimum I had in mind for a "tokenizer". We might consider introducing "character sets" as in Icon (and MIT Scheme?? I vaguely remember seeing something of the sort) to help make this go even faster (since that's the point of the proposal). One procedure could coerce a list of or predicate on characters to a character set, and then the character set specifying the delimiters could be passed to READ-LINE (actually READ-STRING is probably a better name). Finally, I would advocate one extension to the reader itself. That is the inclusion of #+ and #-. We already have added these to the ADS Scheme reader, because we found that it had a tremendous impact on portability of code from one LISP environment to another. Again, this sort of capability is critical for large development efforts or for the production of commercial tools that are intended to work in multiple LISP dialects. I further suggest that "scheme" specifically be recognized by #+ and #- and that "#+scheme" be true in R?RS Scheme. I have used read-time conditionalization in the past and have concluded that it is not a good idea. If a language must have conditionalization, it must have run-time semantics (although of course a compiler can optimize it into load-time or compile-time, depending on what it knows about the target system). The problem with read time conditionalization is that it interacts extremely poorly with cross-compilation, static code analysis, and macros. What I always do is encapsulate implementation dependencies by defining an interface, and then write multiple implementations of the same interface. In my experience this leads to code that's much prettier, more modular, AND more portable. Why won't this work for you? Jonathan.  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 9 Apr 87 21:50:50 EDT Date: Thu, 9 Apr 87 21:49:15 EDT From: Jonathan A Rees Subject: yellow pages To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Thu 9 Apr 87 16:29:05 cdt from David Bartley Message-ID: <182098.870409.JAR@AI.AI.MIT.EDU> Date: Thu, 9 Apr 87 16:29:05 cdt From: David Bartley Perhaps we should discuss a more formal way to share libraries of useful code (a "yellow pages"). Then we could concentrate our standardization efforts on the library interface (modules and environments again!) and other true language features. I agree completely. I think the distinction would be very useful in taking some of the heat out of our discussions, since people needn't be as sensitive about things which have no impact on semantics (and therefore no impact on implementation). We really need to think in general about what the eventual documentary outcome of our next meeting (or two) ought to be. I think a yellow pages of some sort, clearly separated from a description of extensions to the semantics, is definitely in order. Jonathan.  Received: from geneva (TCP 2206400372) by MC.LCS.MIT.EDU 9 Apr 87 20:49:10 EDT Received: by GENEVA.AI.MIT.EDU; Thu, 9 Apr 87 19:11:01 est Date: Thu, 9 Apr 87 19:11:01 est From: jinx@GENEVA.AI.MIT.EDU (Guillermo J. Rozas) Message-Id: <8704100011.AA22486@geneva> To: bartley%home%ti-csl.csnet@RELAY.CS.NET Cc: rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: David Bartley's message of Thu, 9 Apr 87 16:19:28 cdt <8704092119.AA23970@home> Subject: number syntax Has anyone implemented exactness using a mechanism substantially different from the one Kent Dybvig describes in his new book? (Quoting his page 111: "In practice, the internal representation for an exact quantity is as an integer or ratio, and the internal representation for an inexact quantity is as a floating point number, although other representations are possible." Also, "The exactness of a complex numeric object depends on the exactness of its real and imaginary parts.") How do people feel about this approach? Does this fulfill the spirit of exactness? Does anyone want to pay for a more orthogonal exactness attribute for numbers? That is very much against the proposal. We have not implemented it at MIT, but the original proposal is such that both exact and inexact flonums are possible (and desirable), and similarly for the other types. Although we have not implemented it, we have an implementation in mind, and it is orthogonal: for each type of number, there is a bit specifying whether it is exact or not. Is it permissible for an exact 3.5 to print (by default) as 7/2 or an inexact 2 to print as 2.0? It depends on the format specification. For the explicit ones, there should be no question. I think, however, that if the format is (HEUR) it should print as #i2 . Has anyone implemented the -1+2i or 5@7 syntax for complex numbers? Is there strong resistance to Common Lisp's #c(-1 2) representation? CPH has implemented the r^3rs complex notation for MIT Scheme. Having the #c notation should be optional. I don't think the syntax becomes ambiguous if it is added, but there is no need for it. In general, is there anyone strongly opposed to the idea that Scheme number representations should be made to look more like Common Lisp's? Not I, as long as it does not run counter to what the report already states.  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 9 Apr 87 18:48:03 EDT Received: from relay2.cs.net by RELAY.CS.NET id ac25167; 9 Apr 87 18:19 EDT Received: from ti-csl by RELAY.CS.NET id ae00940; 9 Apr 87 18:17 AST Received: from home (home.ARPA) by tilde id AA14868; Thu, 9 Apr 87 15:28:47 cst Received: by home id AA24121; Thu, 9 Apr 87 16:29:05 cdt Date: Thu, 9 Apr 87 16:29:05 cdt From: David Bartley Message-Id: <8704092129.AA24121@home> To: JAR@MC.LCS.MIT.EDU Cc: jinx%geneva.ai.mit.edu@RELAY.CS.NET, bartley%home%ti-csl.csnet@RELAY.CS.NET, rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees's message of Thu, 9 Apr 87 12:38:35 EDT Subject: readers & tokenizers > For things like this (the category also includes multiple values #1, > hash tables, Chris's string-manipulation primitives, and other things I > have mentioned before), we are really in the business of standardizing > on interfaces to libraries of things that can be written portably but > are often better not. We're not talking changes to the language, we're > talking making life easier for those who use these features and people > who read their code. Perhaps we should discuss a more formal way to share libraries of useful code (a "yellow pages"). Then we could concentrate our standardization efforts on the library interface (modules and environments again!) and other true language features.  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 9 Apr 87 18:47:11 EDT Received: from relay2.cs.net by RELAY.CS.NET id af25165; 9 Apr 87 18:19 EDT Received: from ti-csl by RELAY.CS.NET id ac00940; 9 Apr 87 18:17 AST Received: from home (home.ARPA) by tilde id AA14513; Thu, 9 Apr 87 15:19:09 cst Received: by home id AA23970; Thu, 9 Apr 87 16:19:28 cdt Date: Thu, 9 Apr 87 16:19:28 cdt From: David Bartley Message-Id: <8704092119.AA23970@home> To: rrrs-authors@MC.LCS.MIT.EDU Subject: number syntax Before I make another proposal on number syntax, I'd like some feedback on current practice. Has anyone implemented exactness using a mechanism substantially different from the one Kent Dybvig describes in his new book? (Quoting his page 111: "In practice, the internal representation for an exact quantity is as an integer or ratio, and the internal representation for an inexact quantity is as a floating point number, although other representations are possible." Also, "The exactness of a complex numeric object depends on the exactness of its real and imaginary parts.") How do people feel about this approach? Does this fulfill the spirit of exactness? Does anyone want to pay for a more orthogonal exactness attribute for numbers? Is it permissible for an exact 3.5 to print (by default) as 7/2 or an inexact 2 to print as 2.0? Has anyone implemented the -1+2i or 5@7 syntax for complex numbers? Is there strong resistance to Common Lisp's #c(-1 2) representation? In general, is there anyone strongly opposed to the idea that Scheme number representations should be made to look more like Common Lisp's? --db--  Received: from grape.ads.ARPA (TCP 1200400070) by MC.LCS.MIT.EDU 9 Apr 87 17:16:11 EDT Received: by hobbes.ads.arpa (3.2/SMI-3.2) id AA09630; Thu, 9 Apr 87 14:11:51 PDT Date: Thu, 9 Apr 87 14:11:51 PDT From: andy@hobbes.ads.ARPA (Andy Cromarty) Message-Id: <8704092111.AA09630@hobbes.ads.arpa> To: rrrs-authors@mc.lcs.mit.edu Subject: readers & tokenizers One of the difficulties with conventional read tables is that they become very dangerous in a "real" production software environment, relying on lots of Scout's Honor programming practices and usage restrictions. If you write one 10,000 line component of a large system and I write another, there is a risk that you will change the semantics of (READ) out from under me, breaking my code in ways that I will find extremely difficult to debug. To the extent that we are serious about having people use Scheme outside the classroom, this is an important concern. I have used many LISPs that lack both a user-modifiable reader and reader "macros" -- in fact, I have written compilers using those LISPs (including, of course, lexical and syntactic analysis) in a relatively painless fashion. It merely requires good coding practices combined with a little extra effort to build up the lexical analysis subsystem yourself (really a fairly small number of additional functions). I offer this as an "existence proof" of sorts to indicate that we don't really *need* extra gook in the reader, and to suggest that we should be careful about how and why we make it more complex. I have no objection to an improved input system if it is stateless. A trivial new function that would be useful is a (READ-LINE [PORT]) procedure that reads a sequence of characters terminated by NEWLINE or EOF-OBJECT, whichever it encounters first, returning it as a string. A slight extension of this capability would require you to provide the termination character yourself, e.g. (READ-LINE CHAR [PORT]). This can be further extended to take a list of termination characters instead of one character (making it similar to the scanning and breaking functions in SNOBOL), or perhaps a predicate procedure of one argument that returns #T iff the character it is passed is a token terminator, viz. (READ-TOKEN TERMINATOR?-PROC [PORT]). This permits you to perform lexical analysis of an input stream in a quite straightforward fashion without adding significantly to the complexity of the reader for the >90% of the cases where you are just reading symbols, lists, and other objects that the reader already handles well. The advantage I see in such an approach is that all the state is tied up in your predicate or your specific invocation of READ-LINE. There thus is no risk of collisions between different modules, even if they are interleaving reads on the same port. Further, it can be implemented in a quite straightforward fashion. One might object that this could be "inefficient." Such an argument doesn't seem compelling on the face of it, first because a non-stateless reader imposes risks that are significantly more costly than the loss of a few cpu cycles, and second because if we take seriously the suggestion that Scheme should be a useful systems programming language, then such an approach will help ensure that implementors will be pressured into improving the performance of those critical parts of the Scheme system that usually are very slow in LISPs (i.e. readers). I don't know that I want to call this a "proposal," but at least I feel that the spirit of a proposal is there, i.e. that the reader should be stateless if we can find an effective way to achieve that goal. Finally, I would advocate one extension to the reader itself. That is the inclusion of #+ and #-. We already have added these to the ADS Scheme reader, because we found that it had a tremendous impact on portability of code from one LISP environment to another. Again, this sort of capability is critical for large development efforts or for the production of commercial tools that are intended to work in multiple LISP dialects. I further suggest that "scheme" specifically be recognized by #+ and #- and that "#+scheme" be true in R?RS Scheme. asc  Received: from STONY-BROOK.SCRC.Symbolics.COM (TCP 30002424620) by MC.LCS.MIT.EDU 9 Apr 87 17:14:23 EDT Received: from RIO-DE-JANEIRO.SCRC.Symbolics.COM by STONY-BROOK.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 112884; Thu 9-Apr-87 17:07:22 EDT Date: Thu, 9 Apr 87 17:07 EDT From: Kent M Pitman Subject: multiple return values To: jinx@GENEVA.AI.MIT.EDU, JAR@AI.AI.MIT.EDU, adams%tekchips.tek.com@RELAY.CS.NET, ALAN@AI.AI.MIT.EDU, willc%tekchips.tek.com@RELAY.CS.NET cc: RRRS-AUTHORS@MC.LCS.MIT.EDU In-Reply-To: <8703272347.AA03757@tekchips.TEK.COM>, <8703301804.AA09557@geneva> Message-ID: <870409170703.4.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM> The Common Lisp decision to allow additional return values to be silently ignored when unreferenced is an interesting decision but it is certainly not the only position that one can take. The CL specification is muddied by having to explain that there are different kinds of bound variable lists, some of which care how many values are passed through and others of which do not. I would be sad if Scheme went down this road. I think that the Scheme community is in a unique position in being able to see clearly the close relation between returning (invoking functions which are continuations) and calling (invoking functions which are not continuations). I think that in the long run it would be much more valuable to the computer science community as a whole for us to explore the consequences of that close relation than it would be for us to be gratuitously compatible with CL. I think that great advantage in terms of static and dynamic error checking can come from explicitly specifying when these values are to be returned and when not. I think that continuations which take optional or rest arguments are fine as long as they're notated as such. This protects people who want the error checking that comes from return values being mismatched in number and who can afford to pay for that checking. If we adopt a strategy which says that checking is illegal, we're making it very hard for people to get checking. I do agree with a subset of the worry that Alan expressed, though, which is that (+ (F) 3) should work whether F is implemented by (LAMBDA () 4) or (LAMBDA () (RETURN-VALUES 4)). I don't think that: (LAMBDA () (RETURN-VALUES 4 5)) needs to work, though. In fact, I think it should be permitted (and encouraged) to signal an error. I think some syntactic sugar could easily make this palatable; eg, (+ (VALUE 0 (F)) 3)... or better still, (+ (G) 3) where G was a function defined to do what I really meant to be doing.  Received: from Think.COM (TCP 1201000006) by MC.LCS.MIT.EDU 9 Apr 87 16:10:24 EDT Received: from feuerbach by Think.COM via CHAOS; Thu, 9 Apr 87 16:05:08 EST Date: Thu, 9 Apr 87 16:05 EDT From: Guy Steele Subject: readers & tokenizers To: jinx@geneva.ai.mit.edu, JAR@ai.ai.mit.edu Cc: bartley%home%ti-csl.csnet@relay.cs.net, rrrs-authors@mc.lcs.mit.edu, gls@think.com In-Reply-To: <8704091648.AA19230@geneva> Message-Id: <870409160550.5.GLS@FEUERBACH.THINK.COM> Date: Thu, 9 Apr 87 11:48:40 est From: jinx@geneva.ai.mit.edu (Guillermo J. Rozas) I'm not opposed to making available the tokenizer to users. I think that's a good idea. But I really dislike the idea of reader macros, and would much rather make people write their own readers when imbedding/implementing other languages. If by customizable reader you mean tokenizer (as a procedure or set of procedures to invoke on a port, for example), then I don't mind, but I will very strongly oppose anything which allowes users to define #. easily. Connection Machine Lisp would have been considerably more difficult to prototype if not for the availability of the reader-macro facility. --Guy  Received: from geneva (TCP 2206400372) by MC.LCS.MIT.EDU 9 Apr 87 12:49:07 EDT Received: by GENEVA.AI.MIT.EDU; Thu, 9 Apr 87 11:48:40 est Date: Thu, 9 Apr 87 11:48:40 est From: jinx@GENEVA.AI.MIT.EDU (Guillermo J. Rozas) Message-Id: <8704091648.AA19230@geneva> To: JAR@AI.AI.MIT.EDU Cc: bartley%home%ti-csl.csnet@RELAY.CS.NET, rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees's message of Thu, 9 Apr 87 12:38:35 EDT <181778.870409.JAR@AI.AI.MIT.EDU> Subject: readers & tokenizers I'm not opposed to making available the tokenizer to users. I think that's a good idea. But I really dislike the idea of reader macros, and would much rather make people write their own readers when imbedding/implementing other languages. If by customizable reader you mean tokenizer (as a procedure or set of procedures to invoke on a port, for example), then I don't mind, but I will very strongly oppose anything which allowes users to define #. easily.  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 9 Apr 87 12:40:25 EDT Date: Thu, 9 Apr 87 12:38:35 EDT From: Jonathan A Rees Subject: readers & tokenizers To: jinx@GENEVA.AI.MIT.EDU cc: bartley%home%ti-csl.csnet@RELAY.CS.NET, rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Thu 9 Apr 87 09:32:58 est from jinx at GENEVA.AI.MIT.EDU (Guillermo J. Rozas) Message-ID: <181778.870409.JAR@AI.AI.MIT.EDU> Date: Thu, 9 Apr 87 09:32:58 est From: jinx at GENEVA.AI.MIT.EDU (Guillermo J. Rozas) To: bartley%home%ti-csl.csnet at RELAY.CS.NET cc: rrrs-authors at MC.LCS.MIT.EDU, Bartley%home%ti-csl.csnet at RELAY.CS.NET Re: towards an agenda I feel very strongly against customizable readers. I think they are not really very useful, and on the other hand are abused immensely. I've seen plenty of code which I can no longer recognize as Lisp code because of all the reader extensions used in it. I think it is a bad idea to standardaize on one. I sympathize with this. However, the argument I see for this is as follows: many Scheme implementations internally have high-speed tokenizers which either are or could easily be made to be table-driven. If for some reason one writes a Scheme program which needs a tokenizer, a (Pascal, Prolog, ...) compiler for example, one has a choice between writing slow portable code and writing fast unportable code. The speedup can be quite significant; how many implementations have readers that are written using only the i/o primitives in the report? (The reader in the meta-circular Scheme implementation I'm working on comes close, except that it uses PEEK-CHAR.) I'm not going to be precise about what I mean by "tokenizer" but at the very least it means something akin to READ-LINE which stops when it comes upon a "delimiter", and perhaps does some sort of filtering or parsing (e.g. case normalization, escape sequence handling) in the process. Of course, you can in this case use the technique I described in a previous message, of defining your own interface and then making a different bummed implementation of it for each different implementation you actually use. But any situation like this is a candidate for standardization, if more than one person is likely to use it. For things like this (the category also includes multiple values #1, hash tables, Chris's string-manipulation primitives, and other things I have mentioned before), we are really in the business of standardizing on interfaces to libraries of things that can be written portably but are often better not. We're not talking changes to the language, we're talking making life easier for those who use these features and people who read their code. As for defining "read macros" for scheme programs, that's another story. I've never felt much need for this except when emulating one lisp dialect in another, and this application has certainly diminished in importance now that there is some degree of standardization. In cases where I feel I just can't do without, e.g. if I'm playing with some idea for a language design which for some bizarre reason really needs a new read macro, I probably wouldn't mind too terribly writing my own reader, which isn't such a difficult thing, especially if there's already a tokenizer handy. You probably want to do that if you're emulating other dialects (like Common Lisp), too. The peculiar thing about the Common Lisp situation is that it supports read macros, but it doesn't give you any control of the tokenizer. E.g. if you're implementing C and need to distinguish case, you're out of luck. If you want 1A to be an error, or colon to be alphabetic, or ... to be a valid symbol, give up. But then generality was explicitly not one of their design goals in this case. Jonathan  Received: from geneva (TCP 2206400372) by MC.LCS.MIT.EDU 9 Apr 87 10:33:53 EDT Received: by GENEVA.AI.MIT.EDU; Thu, 9 Apr 87 09:32:58 est Date: Thu, 9 Apr 87 09:32:58 est From: jinx@GENEVA.AI.MIT.EDU (Guillermo J. Rozas) Message-Id: <8704091432.AA18976@geneva> To: bartley%home%ti-csl.csnet@RELAY.CS.NET Cc: rrrs-authors@MC.LCS.MIT.EDU, Bartley%home%ti-csl.csnet@RELAY.CS.NET In-Reply-To: David Bartley's message of Wed, 8 Apr 87 15:39:02 cdt <8704082039.AA06501@home> Subject: towards an agenda I feel very strongly against customizable readers. I think they are not really very useful, and on the other hand are abused immensely. I've seen plenty of code which I can no longer recognize as Lisp code because of all the reader extensions used in it. I think it is a bad idea to standardaize on one.  Received: from seismo.CSS.GOV (TCP 30003106431) by MC.LCS.MIT.EDU 9 Apr 87 00:48:41 EDT Received: from munnari.oz by seismo.CSS.GOV (5.54/1.14) with UUCP id AA13684; Wed, 8 Apr 87 22:51:15 EDT Message-Id: <8704090251.AA13684@seismo.CSS.GOV> Received: from goanna by munnari with SunIII (5.5) id AA09438; Thu, 9 Apr 87 12:23:00 EST Date: Thu, 9 Apr 87 10:49:43 EST From: munnari!goanna.oz!hal@seismo.CSS.GOV (Hal Abelson) Received: by goanna.OZ (4.3) id AA14144; Thu, 9 Apr 87 10:49:43 EST To: rrrs-authors@mc.lcs.mit.edu Subject: towards an agenda Bartley's agenda doesn't include error-handling mechanisms. I thought we had decided to worry about that.  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 8 Apr 87 23:55:12 EDT Date: Wed, 8 Apr 87 23:29:15 EDT From: Chris Hanson Subject: multiple values To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <181512.870408.CPH@AI.AI.MIT.EDU> I've finally finished reading all of the mail on this topic, and I'd like to offer a few comments: First, I disagree with Alan when he states that not discarding extra values misses the point of multiple values. In fact, I think there are two things that one gets, which JAR indicated with his message. First, just having multiple values of any kind is useful by itself. The extra functionality of discarding additional values is an additional convenience and not in any way "essential" to the concept of multiple values. Like JAR, I've been using semantics #1 for some time and have found it quite useful, even implemented in Scheme as I have done. Jinx's argument in favor of semantics #2 contains an additional flaw. In fact, the particular example he chose highlights it rather clearly: given an implementation of quotient that returned two values, why is there any particular reason that the first value should be treated specially? In fact, one might be interested in the remainder more often than the quotient, and the order of arguments then enforces a built in prejudice about which value is used more often. Am I then to assume that, to correct for this bias, `remainder' also returns two values, but in the opposite order? Another argument in favor of semantics #1 is that programs written in that semantics will also run in an implementation with semantics #2. On possible way to resolve the conflict is to accept semantics #1 immediately with a provision to upgrade to semantics #2 later if everyone can be convinced that it is reasonable. However, I'd like to propose something different. We have already accepted (I think) that multiple values are optional extensions rather than required. Why not accept BOTH semantics? That gives implementations more flexibility since they can choose between three options: no multiple values, or either of the semantics #1 or #2. People can write programs in any of those forms, with appropriate restrictions to portability: in my case I might choose to write using semantics #1, accepting that my programs will not run in systems without multiple values (or else supplying my own implementation in those cases). Others could write using semantics #2 and accept that their programs would be somewhat less portable. In any case, because multiple values are optional, I think that standard procedures (like `quotient') should not return multiple values. Lastly, I like the names `values' and `with-values'. But I must admit that I wish (with-values (lambda () ) ) would read (with-values . However, I understand why this might be undesirable from the implementor's point of view.  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 8 Apr 87 18:24:44 EDT Received: from relay2.cs.net by RELAY.CS.NET id ab14032; 8 Apr 87 17:50 EDT Received: from ti-csl by RELAY.CS.NET id ab23460; 8 Apr 87 17:46 AST Received: from home (home.ARPA) by tilde id AA15867; Wed, 8 Apr 87 14:38:40 cst Received: by home id AA06501; Wed, 8 Apr 87 15:39:02 cdt Date: Wed, 8 Apr 87 15:39:02 cdt From: David Bartley Message-Id: <8704082039.AA06501@home> To: rrrs-authors@MC.LCS.MIT.EDU Cc: Bartley%home%ti-csl.csnet@RELAY.CS.NET Subject: towards an agenda I had hoped to propose an agenda here, but I tripped over too many unknowns, so let's try to nail a few things down first. Is there agreement on which days we will meet? Jonathan, can you suggest which hours of the day will be available for scheduling? Can everyone arrange to attend? Will and I suggested the following topics that we would like to see resolved: 1. multiple return values 2. customizable reader 3. number syntax and exactness 4. macros 5. optional arguments 6. structures and opaque objects (& set!, maybe) 7. environments and modules These are roughly in descending order of priority as we see it. We already have proposals for 1, 4, and 5. Will hopes to cover 2 soon. I suggested a more Common Lisp-like number syntax last year, so I'll plan to clean that up and propose it again. Kent Dybvig's book contains some language about exactness that I'd like to comprehend in my proposal. Chez Scheme and TI Scheme (and perhaps others) have somewhat contradictory define-structure features, so it would be nice to head off further divergence in that area. Although topic 7, environments and modules, is last on the list, I see it as having long-term impact on whether Scheme continues to be used for ever larger and larger "production" systems. "Programming in the large" is a serious challenge for everyone looking to Lisp dialects for new programming paradigms right now, and I'd like to find a way to give Scheme an edge over other languages. Other topics were suggested at the 1986 Lisp conference luncheon, e.g. a way to declare that a variable such as CAR is never assigned. Would anyone care to propose any of them for discussion at our next meeting? --db--  Received: from mitre-bedford.ARPA (TCP 3200600102) by MC.LCS.MIT.EDU 8 Apr 87 12:20:08 EDT Posted-From: The MITRE Corp., Bedford, MA Received: from relay2.cs.net by RELAY.CS.NET id ai04077; 7 Apr 87 17:07 EDT Received: from ti-csl by RELAY.CS.NET id ao16423; 7 Apr 87 17:05 AST Received: from home (home.ARPA) by tilde id AA17230; Tue, 7 Apr 87 14:48:35 cst Received: by home id AA18814; Tue, 7 Apr 87 15:48:56 cdt Date: Tue, 7 Apr 87 15:48:56 cdt From: David Bartley Message-Id: <8704072048.AA18814@home> To: ramsdell%faron@mitre-bedford.ARPA Cc: rrrs-authors%mc.lcs.mit.edu@mitre-bedford.ARPA In-Reply-To: "John D. Ramsdell"'s message of Tue, 7 Apr 87 07:44:26 est Subject: macros > Date: Tue, 7 Apr 87 07:44:26 est > From: "John D. Ramsdell" > > Multiple returns and optional arguments are interesting > to discuss, but everybody uses macros. It seems to me > that an agreement on macros is much more important. I agree that it is equally important, but harder to resolve. > JAR's > proposal appears to satisfy most needs for macros. At first > I worried about the added complexity of specifying macros, but > now I think that its good to discourage its use by making it > hairy. I can't agree that any language feature should be made hairy in order to discourage its use. If a feature deserves to be in Scheme then it deserves to be done right. You (or I, at least) can't morally discourage the use of a feature by booby-trapping it with excess complexity. > Do I understand the lack of discussion to mean that > there are no objections to JAR's proposal? If so, let's adopt > it and move on. No, I at least just haven't finished preparing a response. His proposal is detailed, has much merit, and deserves serious study. This topic is *much* more complicated than the others raised so far, so it's hard to critique one proposal without suggesting alternatives. > John --db--  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 7 Apr 87 21:19:09 EDT Date: Tue, 7 Apr 87 21:17:08 EDT From: Jonathan A Rees Subject: Taste To: RPG@SAIL.STANFORD.EDU cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of 06 Apr 87 1334 PDT from Dick Gabriel Message-ID: <180826.870407.JAR@AI.AI.MIT.EDU> Date: 06 Apr 87 1334 PDT From: Dick Gabriel I was under the impression that people on this list were not required to explain why they thought something was in bad taste nor provide alternatives. Jonathan wrote recently: ``I would strongly oppose the Common Lisp multiple value semantics. I find it to be very distasteful.'' There was no further discussion of reasons or alternatives. No one asked... if you care to know, it's because I think ignored values, as well optional arguments for that matter, are a form of overloading, and overloading is a kind of pun, and punning is to be avoided where possible, since (in my opinion) it's likely to lead to code that's buggy and/or unreadable and/or not well thought out. Sometimes overloading is just what you want in order for your code to be modular, but I haven't observed that in these situations. This is all very vague, of course, which is why I waved my hands. The line: (LAMBDA (X Y Z . R) ...) puts a lot semantic emphasis on the character `.'. It relies on a joke involving the (coincidental) underling data structure that is sometimes used to represent expressions. I agree, this is a feature of dubious design. This probably ought to be written (LAMBDA ARGS (... something which takes apart ARGS ...)). Perhaps the n-ary version of LAMBDA ought to have a different name. The line that starts (OPTIONALS ...) is simply a recovery from the language design error reflected on the previous line. I think that if we (may I be so bold?) are considering a richer parameter-passing language, we should carefully consider and decide what information we wish to have expressed regarding how variables will be bound upon function entry. Possibly we want to define a language for passing structures of various types which will then be decomposed and bound upon function entry - this would be much like alien structure languages in some languages. The advantage of Common Lisp &-markers is that it is relatively clear that something funny is going on, and a programmer doesn't have to rely on a human reader to always see the tiny `.'. I know of no instance where someone has failed to see the dot, or where someone has been confused about its basic meaning... a bigger problem with it than its small size is the fact that you can't write (LAMBDA (. R) ...) (which, by the way, is legal in T, and it does what you'd expect). &REST, #!REST, &DOT, |.|, etc., it is true, do not suffer from this problem. If the strategy is to be able to pass an arbitrary number of arguments, then a syntax that binds one variable to all of them following by a pretty destructuring bind of some sort is much better than a syntax that mixes required with &rest (as Jonathan suggested). I agree. In my experience, pattern-matching languages seem to have an inevitable tendency to become baroque and disgusting. But let's not stop looking for a decent one. Thanks for explaining. Jonathan...  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 7 Apr 87 16:35:13 EDT Date: Tue, 7 Apr 87 16:33:22 EDT From: Jonathan A Rees Subject: macros To: ramsdell%faron@MITRE-BEDFORD.ARPA cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Tue 7 Apr 87 07:44:26 est from John D. Ramsdell Message-ID: <180699.870407.JAR@AI.AI.MIT.EDU> Date: Tue, 7 Apr 87 07:44:26 est From: John D. Ramsdell Multiple returns and optional arguments are interesting to discuss, but everybody uses macros. It seems to me that an agreement on macros is much more important. JAR's proposal appears to satisfy most needs for macros. At first I worried about the added complexity of specifying macros, but now I think that its good to discourage its use by making it hairy. Do I understand the lack of discussion to mean that there are no objections to JAR's proposal? If so, let's adopt it and move on. I believe there are serious objections from Gene Kohlbecker and/or Dan Friedman, at least. Gene is off the net, but I'll get in touch with him. Perhaps Dan will overcome his shyness and let us know why an "unhygienic" least common denominator is the wrong thing. Jonathan  Received: from Think.COM (TCP 1201000006) by MC.LCS.MIT.EDU 7 Apr 87 11:07:05 EDT Received: from godot.think.com by Think.COM; Tue, 7 Apr 87 11:02:33 EST Received: from thorlac by godot.think.com via CHAOS; Tue, 7 Apr 87 11:02:22 EST Date: Tue, 7 Apr 87 10:03 EST From: Guy Steele Subject: Optionals To: JAR@ai.ai.mit.edu, RPG@sail.stanford.edu Cc: rrrs-authors@mc.lcs.mit.edu In-Reply-To: <179987.870406.JAR@AI.AI.MIT.EDU> Message-Id: <870407100325.3.GLS@THORLAC.THINK.COM> Date: Mon, 6 Apr 87 16:10:23 EDT From: Jonathan A Rees ... Please ... explain to me whether or not the following is legal Common Lisp and what it returns: ((lambda (&rest foo &key ((foo foo) 3 foo)) foo) :foo 5 :foo 8 :allow-other-keys nil :allow-other-keys 13) RPG did not respond to this point in his reply, so I will take the liberty here: There are three distinct areas that you are muddling here. One is the question of whether Common Lisp specifies the meaning of this expression precisely and unambiguously. The second is whether the facilities of the language can be abused to produce unreadable code. The third is, if the scond is true, does the language design encourage such abuse. The existing Common Lisp specification unfortunately is not entirely precise unambiguous. For example, it does not address the question of whether there may be two parameters of the same name in a single lambda-list. (The latest sentiment I have observed is that it should be an error.) On the other hand, the first keyword argument FOO will be bound to 5, not 8; that is specified on page 62. You have raised an interesting point concerning :allow-other-keys; the wording of the second bulleted point on page 63 is unfortunately inconsistent with the statement on page 62 about taking the leftmost pair. I think we have already seen in the last week how easy it is to produce unreadable code, and I will not belabor the point here beyond the simple assertion that it simply IS NOT A VALID ARGUMENT to assert that a language is bad because it is possible to write programs that are difficult to understand. Now, if you had argued that the design of Common Lisp actively encourages such abuse, rather than merely permitting it, I would be sympathetic.  Received: from mitre-bedford.ARPA (TCP 3200600102) by MC.LCS.MIT.EDU 7 Apr 87 08:44:44 EDT Full-Name: Posted-From: The MITRE Corp., Bedford, MA Received: by faron.MENET (4.12/4.7) id AA08662; Tue, 7 Apr 87 07:44:26 est Date: Tue, 7 Apr 87 07:44:26 est From: John D. Ramsdell Posted-Date: Tue, 7 Apr 87 07:44:26 est Message-Id: <8704071244.AA08662@faron.MENET> To: rrrs-authors%mc.lcs.mit.edu@mitre-bedford.ARPA Subject: macros Multiple returns and optional arguments are interesting to discuss, but everybody uses macros. It seems to me that an agreement on macros is much more important. JAR's proposal appears to satisfy most needs for macros. At first I worried about the added complexity of specifying macros, but now I think that its good to discourage its use by making it hairy. Do I understand the lack of discussion to mean that there are no objections to JAR's proposal? If so, let's adopt it and move on. John  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 6 Apr 87 17:09:14 EDT Date: Mon, 6 Apr 87 16:10:23 EDT From: Jonathan A Rees Subject: Optionals To: RPG@SAIL.STANFORD.EDU cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of 06 Apr 87 1144 PDT from Dick Gabriel Message-ID: <179987.870406.JAR@AI.AI.MIT.EDU> Date: 06 Apr 87 1144 PDT From: Dick Gabriel As one of the sad, major forces behind Common Lisp, I'm glad to see that Common Lisp doesn't have a monopoly on bad taste. The only palletable line in this code reads: -body-)) Don't be elliptical. Please elaborate, explain why tasteless, propose alternative, and explain to me whether or not the following is legal Common Lisp and what it returns: ((lambda (&rest foo &key ((foo foo) 3 foo)) foo) :foo 5 :foo 8 :allow-other-keys nil :allow-other-keys 13) PS I don't find "palletable" in my dictionary. I do find pallet n. 1. a wooden flat-bladed instrument 2. a lever or surface in a timepiece that receives an impulse fom the escapement wheel and imparts motion to a balance or pendulum 3. a portable platform for handling, storing or moving materials and packages (as in warehouses, factories, or vehicles) palletize vt. to place on, transport, or store by means of pallets Perhaps you mean "palletizable"? J.  Received: from SAIL.STANFORD.EDU (TCP 1200000013) by MC.LCS.MIT.EDU 6 Apr 87 16:40:54 EDT Date: 06 Apr 87 1334 PDT From: Dick Gabriel Subject: Taste To: rrrs-authors@MC.LCS.MIT.EDU Sorry, I mispelled ``palatable.'' I was under the impression that people on this list were not required to explain why they thought something was in bad taste nor provide alternatives. Jonathan wrote recently: ``I would strongly oppose the Common Lisp multiple value semantics. I find it to be very distasteful.'' There was no further discussion of reasons or alternatives. The line: (LAMBDA (X Y Z . R) ...) puts a lot semantic emphasis on the character `.'. It relies on a joke involving the (coincidental) underling data structure that is sometimes used to represent expressions. The line that starts (OPTIONALS ...) is simply a recovery from the language design error reflected on the previous line. I think that if we (may I be so bold?) are considering a richer parameter-passing language, we should carefully consider and decide what information we wish to have expressed regarding how variables will be bound upon function entry. Possibly we want to define a language for passing structures of various types which will then be decomposed and bound upon function entry - this would be much like alien structure languages in some languages. The advantage of Common Lisp &-markers is that it is relatively clear that something funny is going on, and a programmer doesn't have to rely on a human reader to always see the tiny `.'. If the strategy is to be able to pass an arbitrary number of arguments, then a syntax that binds one variable to all of them following by a pretty destructuring bind of some sort is much better than a syntax that mixes required with &rest (as Jonathan suggested). -rpg-  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 6 Apr 87 15:38:24 EDT Date: Mon, 6 Apr 87 15:03:55 EDT From: Jonathan A Rees Subject: optional arguments To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: RRRS-Authors@MC.LCS.MIT.EDU In-reply-to: Msg of Mon 6 Apr 87 11:13:06 cdt from David Bartley Message-ID: <179940.870406.JAR@AI.AI.MIT.EDU> Date: Mon, 6 Apr 87 11:13:06 cdt From: David Bartley This appears to be more of a destructuring form than one restricted to defining optional arguments. Would you allow the (OPTIONAL ...) to appear anywhere or just directly inside a LAMBDA as its body? Must the second "argument" (R) be the name of a "rest" arg? It can appear anywhere, and R can be any list. In other words, it's the obvious macro, nothing more or less, semantically at least. (The syntax "(OPTIONAL r ((var default) ...) body)" is probably better than "(OPTIONAL ((var default) ...) r body)".) It apparently only allows destructuring at the top level of a list. My use of the term "destructuring" was a little too free then. Your proposal also only allows it at top level, yes? Mixing default values with full destructuring would be awful... My suggestion can also be implemented straightforwardly as a macro. Into what would it expand? You would still need either (1) a PRIMITIVE-LAMBDA expression type, (2) an incompatible LAMBDA in some distinct syntax table, or (3) the ability to overload macros. I think there are problems with all three approaches. I prefer the orthogonal approach of giving distinct features distinct names. (Well... why does LAMBDA support rest-arguments, you ask? And why does the language have "named LET"? I remember that Dan Friedman argued against overloading LAMBDA for n-ary procedures back in '84, for exactly this reason. I vacillate between agreeing with him and not. I argued against named LET, but other people said you can view unnamed LET as a special case of named LET, therefore the overloading is OK, and desirable because you want to minimize the number of reserved words at almost any cost. They shouted more loudly, and won.) I like this notation, but not the idea that its efficiency depends on the cleverness of the compiler, since that inhibits using such features in portable code. It would require a compiler to determine whether the declared rest arg R were otherwise referenced from within the body of the procedure in order to approach the efficiency a dumb compiler could get with my approach. As Alan Bawden asked, since when were efficiency considerations so important in language design? However, I don't think OPTIONAL need be inefficient. Sure, it needs a two-pass compiler, but given that, detecting the situation is trivial, much easier than detecting whether a LETREC is a loop or that an environment may be allocated on a stack or in registers. I assume the PC Scheme compiler and most others are already two-pass, so I don't think this is a big deal. I don't know of anyone who is using a pure interpreter these days. If you're concerned about the speed of portable code, I'd say this is probably the least of your worries. Other kinds of unnecessary consing, especially of environments, procedures, and continuations, will dominate this kind if the compiler is only one-pass. (But is it proper for one macro to assume that another macro has not been redefined?) The answer is no, if syntactic keywords are scoped at all (and they ought to be) then it is definitely not proper, but that doesn't mean a macro has no hope of examining subforms. Did you read my macro proposal? You could deal with situations like this if there was some way to examine preprocessed expressions. The ->CORE procedure in the proposal would suffice if OPTIONAL-expressions were in its range. But I think it would be better to put it in the compiler, especially since the case without the rest-argument is the important one for error checking. You don't want people to forego the error checking -- one of the main reasons having an explicit optional-argument feature comes up -- just in order to reduce consing, and you don't want macros doing optimizations in any case. Jonathan.  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 6 Apr 87 14:52:52 EDT Date: Mon, 6 Apr 87 14:20:42 EDT From: Jonathan A Rees Subject: current membership To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <179905.870406.JAR@AI.AI.MIT.EDU> Enclosed is the current membership of RRRS-AUTHORS. Sometime in February or March I added two members of the Eulisp committee, Julian Padget and Andy Norman. Most list members seem to be observers rather than participants, which I take to be a sign that we're doing something right. We could use a new name for the mailing list, since "RRRS-authors" hasn't been appropriate since the R^2 report came out (a year and a half ago). Maybe something like "Scheme-authors" or "Scheme-designers" or "Scheme-report-authors". "R^NRS-authors" isn't pronounceable. - Jonathan ;;; MIT: (file [LSPMAI;RRRS MAIL]) ;Local archive file SCHEME-RRRS@OZ.AI.MIT.Edu ;Oz people alco@VX.LCS.MIT.Edu ;Dave Alcocer LS.SRB@Deep-Thought.MIT.Edu ;Steve Balzac ALAN ;Alan Bawden Ziggy@VX.LCS.MIT.Edu ;Michael Blair RHH ;Bert Halstead CPH ;Chris Hanson NICK ;Nick Papadakis JAR ;? ;;; Non-MIT: jleech@ADS.ARPA ;ADS / Jay Leech william@ADS.ARPA ; William Bricken andy@ADS.ARPA ; Andy Cromarty padget%uk.ac.bath.ux63@CS.UCL.AC.UK ;Bath / Julian Padget HP-SCHEME@HPLABS.HP.Com ;HP / Henry Wu ange%hplb.csnet@Relay.CS.Net ; Andy Norman dyb%indiana@Relay.CS.Net ;Indiana/ Kent Dybvig scheme-rrrs%indiana@Relay.CS.Net ;Indiana / ... linus!ramsdell@Mitre-Bedford.ARPA ;MITRE / John Ramsdell wand%corwin.ccs.northeastern.edu@Relay.CS.Net ;Northeastern / Mitch Wand ("#COMSCH.MSG[SCH,LSP]" @SAIL.Stanford.Edu) ;Stanford / file archive ANDY@Sushi.Stanford.Edu ; Andy Freeman RPG@SAIL.Stanford.Edu ; Dick Gabriel Daniel ; Daniel Weise RDZ ; Ramin Zabih KMP ;Symbolics / Kent Pitman adams%tekchips%tektronix@Relay.CS.Net ;Tektronix / Norman Adams willc%tekchips%tektronix@Relay.CS.Net ; Will Clinger rrrs-authors-incoming%TI-CSL@Relay.CS.Net ;TI / ... GLS ;TMI / Guy Steele patel@CS.UCLA.EDU ;UCLA / Dorab Patel Hudak@Yale.ARPA ;Yale / Paul Hudak Kelsey@Yale.ARPA ; Richard Kelsey Kranz@Yale.ARPA ; David Kranz Philbin-Jim@Yale.ARPA ; Jim Philbin  Received: from SAIL.STANFORD.EDU (TCP 1200000013) by MC.LCS.MIT.EDU 6 Apr 87 14:48:44 EDT Date: 06 Apr 87 1144 PDT From: Dick Gabriel Subject: Optionals To: rrrs-authors@MC.LCS.MIT.EDU Jonathan proposes: (LAMBDA (A B . R) (OPTIONAL ((X 1) (Y (+ X 5))) R -body-)) As one of the sad, major forces behind Common Lisp, I'm glad to see that Common Lisp doesn't have a monopoly on bad taste. The only palletable line in this code reads: -body-)) -rpg-  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 6 Apr 87 12:58:28 EDT Received: from relay2.cs.net by RELAY.CS.NET id aj14655; 6 Apr 87 12:36 EDT Received: from ti-csl by RELAY.CS.NET id at06040; 6 Apr 87 12:35 AST Received: from home (home.ARPA) by tilde id AA06696; Mon, 6 Apr 87 10:12:42 cst Received: by home id AA23220; Mon, 6 Apr 87 11:13:06 cdt Date: Mon, 6 Apr 87 11:13:06 cdt From: David Bartley Message-Id: <8704061613.AA23220@home> To: JAR@MC.LCS.MIT.EDU Cc: Bartley%home%ti-csl.csnet@RELAY.CS.NET, RRRS-Authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees's message of Fri, 3 Apr 87 16:47:09 EST Subject: optional arguments > Date: Fri, 3 Apr 87 16:47:09 EST > From: Jonathan A Rees > > I have a different optional arguments proposal, which people should keep > in mind as an alternative: > > Don't make any change to the syntax of LAMBDA. Instead, just introduce > a new special form for taking apart rest arguments. Example: > > (LAMBDA (A B . R) > (OPTIONAL ((X 1) (Y (+ X 5))) R > -body-)) This appears to be more of a destructuring form than one restricted to defining optional arguments. Would you allow the (OPTIONAL ...) to appear anywhere or just directly inside a LAMBDA as its body? Must the second "argument" (R) be the name of a "rest" arg? > [...] > I think this gets most of the benefits you want without making LAMBDA > hairy. It provides parameter list destructuring and error checking in a > nice orthogonal way, and is only a little bit more verbose than hairy > LAMBDA-isms. And it can be implemented in straightforwardly as a macro. It apparently only allows destructuring at the top level of a list. My suggestion can also be implemented straightforwardly as a macro. > [...] > Effiency note: the mythical "sufficiently clever compiler" can avoid > consing the rest-list if there's only the one reference to R. I think > this would be a very straightforward transformation. I like this notation, but not the idea that its efficiency depends on the cleverness of the compiler, since that inhibits using such features in portable code. It would require a compiler to determine whether the declared rest arg R were otherwise referenced from within the body of the procedure in order to approach the efficiency a dumb compiler could get with my approach. On the other hand, if one customarily wrote (LAMBDA (A B . R1) (OPTIONAL ((X 1) (Y (+ X 5)) . R2) R1 -body-)) with the variables R1 and R2 having the same name, then a preprocessor for LAMBDA could "look ahead" for an OPTIONAL form in its body and determine that R1 could possibly have but one use. This would be a fairly localized test. (But is it proper for one macro to assume that another macro has not been redefined?) Regards, David Bartley  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 3 Apr 87 16:47:46 EST Date: Fri, 3 Apr 87 16:47:09 EST From: Jonathan A Rees Subject: optional arguments To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: RRRS-Authors@MC.LCS.MIT.EDU In-reply-to: Msg of Fri 3 Apr 87 09:55:18 cst from David Bartley Message-ID: <178851.870403.JAR@AI.AI.MIT.EDU> I have a different optional arguments proposal, which people should keep in mind as an alternative: Don't make any change to the syntax of LAMBDA. Instead, just introduce a new special form for taking apart rest arguments. Example: (LAMBDA (A B . R) (OPTIONAL ((X 1) (Y (+ X 5))) R -body-)) would be analogous to the Comon Lisp lambda-expression (LAMBDA (A B &OPTIONAL (X 1) (Y (+ X 5))) -body-), and (LAMBDA (A B . R) (OPTIONAL ((X 1) (Y (+ X 5)) . R) R -body-)) would be like (LAMBDA (A B &OPTIONAL (X 1) (Y (+ X 5)) &REST R) -body-), I think this gets most of the benefits you want without making LAMBDA hairy. It provides parameter list destructuring and error checking in a nice orthogonal way, and is only a little bit more verbose than hairy LAMBDA-isms. And it can be implemented in straightforwardly as a macro. I have had this in the back of my mind since about 1981. I never got around to installing it in T, but I should have. I have implemented and used it on several occasions (e.g. for implementing R^2 Scheme in T), and was fairly happy with it. Effiency note: the mythical "sufficiently clever compiler" can avoid consing the rest-list if there's only the one reference to R. I think this would be a very straightforward transformation. Jonathan  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 3 Apr 87 13:39:18 EST Received: from relay2.cs.net by RELAY.CS.NET id aa04453; 3 Apr 87 10:21 EST Received: from ti-csl by RELAY.CS.NET id aj00816; 3 Apr 87 11:18 EST Received: from home (home.ARPA) by tilde id AA19574; Fri, 3 Apr 87 09:55:04 cst Received: by home id AA16369; Fri, 3 Apr 87 09:55:18 cst Date: Fri, 3 Apr 87 09:55:18 cst From: David Bartley Message-Id: <8704031555.AA16369@home> To: RRRS-Authors@MC.LCS.MIT.EDU Cc: Bartley%home%ti-csl.csnet@RELAY.CS.NET Subject: optional arguments And now for something completely different... I believe it is time to consider adopting a simple extension to the syntax for formal argument lists in Lambda expressions to include optionally supplied arguments. Here's a proposal that seems to codify the essentials of existing practice in at least a few implementations. MOTIVATION It was successfully argued at Brandeis that "rest" arguments suffice for the definition of procedures that take arbitrary numbers of actual arguments. Although this is certainly true, it has at least three disadvantages. First, a direct implementation of optional arguments could be more efficient by avoiding the extra consing needed for a fully general rest argument. Second, error checking is more sporadic when programmers supply their own mechanisms. It is cumbersome to specify a finite number of optional arguments given the open ended nature of rest args. Third, providing for optional arguments is so common a paradigm that readability and portability would be enhanced if we could agree on a standard mechanism. ISSUES I see several issues to be resolved: (1) An extended syntax allowing optional arguments must be compatible with the existing standard for Scheme. It is also desirable that it not conflict with existing extensions for optional arguments and existing or proposed extensions in other directions. (For example, anyone favoring an extension of formal parameter lists to allow destructuring of arguments has few available syntactic alternatives.) (2) It must be decided whether a full or barebones facility should be standardized. If the latter, the extended syntax for optionals should also allow for further extension. (3) It should be possible to determine at run time whether a particular optional argument was supplied by the caller. One way to do this is to supply a count of the number of arguments passed to the called procedure. Another way is to allow the called procedure to ask whether a given argument were supplied. (4) It is useful to allow specification of values to be bound to optional arguments when actual parameters are not supplied by the caller. This facility is convenient but can be built upon the ability to determine whether a value had been supplied by the caller. It also has subtle problems, such as the exact lexical environment to be used in evaluating the initializing expression. INFORMAL DESCRIPTION I suggest that we adopt the following mechanism for optional arguments as a non-essential feature. It is basically the approach used internally here at TI based on our understanding of a similar facility in MIT Scheme. However, it includes modifications suggested by Will Clinger. -- Formal argument lists containing optional arguments are distinguished by the presence of the keyword #!OPTIONAL, which acts like &OPTIONAL in Common Lisp. (I could write out an informal description here based on Steele's book, but there's no need to yet.) -- Formal variables which do not receive values are said to be "bound" but not "assigned". It is an error to reference an unassigned variable. Ideally, an implementation would trap on such references. However, it may choose to mark unassigned variables with a distinguished value (or values), such as the token #!UNASSIGNED. (The R^3RS formal semantics assumes that all variables are bound in the initial environment, but this is an area where implementations differ. Some implementations may extend the syntax for DEFINE so (DEFINE X) creates a binding for X but leaves it unassigned.) The special form (ASSIGNED? ) returns #T iff the variable named by has been assigned a value (e.g., from the calling procedure's actual argument list). The value of (ASSIGNED? X) is unspecified if X is unbound. For example the value of (LETREC ((X (ASSIGNED? X))) X) is not clear, just as the value of (LETREC ((X X)) X) is unspecified. -- A "rest" argument is always assigned. If the list of actual arguments is no longer than the number of required and optional formals, the rest argument receives the value (). -- Optional arguments may be given default values by first testing them with ASSIGNED? as in the following example: (lambda (a #!optional b) (let ((b (if (assigned? b) b (+ a 42)))) ...)) or (lambda (a #!optional b) (when (not (assigned? b)) (set! b (+ a 42))) ...) This makes clear the environment that the initialization expression for B is to be evaluated in. FORMAL SEMANTICS Will Clinger has kindly volunteered the following formal semantics for ASSIGNED? and LAMBDA. The "\" character should be read as Greek lambda. E [[ (assigned? I) ]] = \ r k . hold (lookup r I) (single (\ e . e = undefined --> false, true)) E [[ (lambda (I0* #!optional I1*) C* E0 ]] = \ r k . \ s . new s \in L --> send (< new s | L, \ e* k' . (# e* >= # I0*) & (# e* <= (# I0* + # I1*)) --> tievals (\ a* . (\ r' . C [[ C* ]] r' (E [[ E0 ]] r' k')) (extends r (I0* concat I1*) a*)) (e* concat (seq (# I0* + # I1* - # e*) undefined)), wrong "wrong number of arguments"> in E) k (update (new s | L) unspecified s), wrong "out of memory" s E [[ (lambda (I0* #!optional I1* . I) C* E0 ]] = \ r k . \ s . new s \in L --> send (< new s | L, \ e* k' . # e* >= # I0* --> tievalsrest (\ a* . (\ r' . C [[ C* ]] r' (E [[ E0 ]] r' k')) (extends r (I0* concat I1* concat ) a*)) ((takefirst e* (# I0*)) concat (seq (# I0* + # I1* - # e*) undefined) concat (dropfirst e* (# I0*))) (# I0* + # I1*), wrong "too few arguments"> in E) k (update (new s | L) unspecified s), wrong "out of memory" s where seq = \ n x . n <= 0 --> <>, concat (seq (n - 1) x) DISCUSSION I don't propose a syntactic extension for specifying default initialization more conveniently because (1) the obvious syntax would conflict with an extension for argument list destructuring; (2) testing whether a variable had been supplied by the caller or from evaluation of the default initialization expression becomes more complicated; (3) the explicit mechanism given here seems quite readable and convenient to me; and (4) I think it's important to make explicit which environment the initialization form is evaluated in and to allow variations. I've mentioned destructuring several times because I have the impression much of the opposition to optional arguments comes from the desire to leave the way open for destructuring lambda lists. It seems to me that the simple addition of the #!OPTIONAL keyword should not seriously hinder destructuring, since it is unambiguous and can be easily recognized. I welcome all comments. Regards, David Bartley  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 2 Apr 87 13:33:13 EST Received: from relay2.cs.net by RELAY.CS.NET id ad22936; 2 Apr 87 13:11 EST Received: from ti-csl by RELAY.CS.NET id ad00800; 2 Apr 87 13:03 EST Received: from home (home.ARPA) by tilde id AA18814; Thu, 2 Apr 87 10:49:03 cst Received: by home id AA02024; Thu, 2 Apr 87 10:49:21 cst Date: Thu, 2 Apr 87 10:49:21 cst From: David Bartley Message-Id: <8704021649.AA02024@home> To: CPH@MC.LCS.MIT.EDU Cc: JAR@MC.LCS.MIT.EDU, rrrs-authors@MC.LCS.MIT.EDU, Bartley%home%ti-csl.csnet@RELAY.CS.NET In-Reply-To: Chris Hanson's message of Wed, 1 Apr 87 21:51:51 EST Subject: multiple return values > Date: Wed, 1 Apr 87 21:51:51 EST > From: Chris Hanson > > Date: Tue, 31 Mar 87 22:13:26 EST > From: Jonathan A Rees > > I would strongly oppose the Common Lisp multiple value semantics. I > find it to be very distasteful. If this means that the language has no > multiple values primitively, and I have to implement semantics #1 myself > using lists or closures or whatever, that's fine with me. > > If I have many sympathizers then I'd say it appears that we're > as deadlocked as we were last time this came up... > > I think that I agree with JAR... I've just got back from vacation and > have not yet read all the mail on this (at 1200 baud, I'll wait for > work tomorrow!), but I am very disturbed by the direction this is > taking. I don't see a need for a complicated semantics! I'll reply > more fully later when I've had a chance to read all of this. I hope we can at least agree on the names and the syntax for a standard facility. I agree that we shouldn't STANDARDIZE on anything complicated, but that we should have the basis for extensions in the direction of Common Lisp for those of us that want it. > Date: Sun, 29 Mar 87 02:29:12 EST > From: Alan Bawden > > I will confine myself to reminding you of what I said the last time this > subject was raised: Any implementation of multiple-values that doesn't > have the property that ordinary continuations (for example the continuation > passed to F in (+ (F) 3)) will accept and ignore extra values has missed > the point of multiple values. This is why I prefer alternative #2. > Let me try putting it another way: If you decide on a semantics for > multiple values that has the property that a correct implementation can be > written in straight R^3RS Scheme, then what have you accomplished? You > haven't given the users anything they couldn't have written for themselves. > (Yes, perhaps you can arrange to implement it more efficiently, but since > when has that been the the spirit of the language?) I would prefer this to no agreement at all. Can we avoid deadlock? Regards, David Bartley  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 2 Apr 87 13:32:41 EST Received: from relay2.cs.net by RELAY.CS.NET id ac22936; 2 Apr 87 13:11 EST Received: from ti-csl by RELAY.CS.NET id ac00800; 2 Apr 87 13:02 EST Received: from home (home.ARPA) by tilde id AA18402; Thu, 2 Apr 87 10:31:31 cst Received: by home id AA01664; Thu, 2 Apr 87 10:31:45 cst Date: Thu, 2 Apr 87 10:31:45 cst From: David Bartley Message-Id: <8704021631.AA01664@home> To: jinx%geneva.ai.mit.edu@RELAY.CS.NET Cc: RRRS-Authors@MC.LCS.MIT.EDU, Bartley%home%ti-csl.csnet@RELAY.CS.NET In-Reply-To: "Guillermo J. Rozas"'s message of Wed, 1 Apr 87 22:53:32 est Subject: multiple return values (LONG) > (1) I agree with ALAN and Jinx that it seems pretty useless to specify > a multiple value capability and not go beyond Will's alternative #1. > Since I intend to implement Common Lisp on top of Scheme, I will want > to extend the essential capability anyway. (Are ALAN and Jinx arguing > for #2 or #3?) > I like #2. More about this below. JINX makes a pretty good case for #2 and I'm persuaded. More below. Scratch the term "useless"---standardizing on #1 at least gives us a common basis for our various extensions. > (4) It seems to me that the hairiest part of the multiple value > "feature" in Common Lisp is MULTIPLE-VALUE-PROG1. Something like this > [...] > > I think it is worth thinking about, but given that the above is > sufficient, I don't think there is a need to standardize. OK. > (5) JAR finds the proposed feature "to be pretty unuseable unless > there is some syntactically sugared way to use RECEIVE-VALUES." If > this is true, I think we must agree on what sugar to add. What's the > point of standardizing on something that is too cryptic to be used by > anyone? > > I like T's RECEIVE [...] > > If we keep the name RECEIVE-VALUES, then the name RECEIVE is ok here, > but I would prefer something like MULTIPLE-VALUE-LET. > > What about MULTIPLE-VALUE-BIND? The syntax is not like LET at all, > and it really is similar to the CL construct. Upon reflection, I wonder if there really is a problem. Does anyone else feel that the proposal is "pretty unuseable unless there is some syntactically sugared way to use RECEIVE-VALUES" or that it is "too cryptic"? I don't. > (6) Let's get down to brass tacks and argue about names! [...] > > I don't care much about the names of procedures, but I agree with GLS. > What's wrong with VALUES? Another possibility for RECEIVE-VALUES is > MULTIPLE-VALUE-COMPOSE, or even, CALL-EXPECTING-MULTIPLE-VALUES. OK. I like VALUES or MULTIPLE-VALUES instead of RETURN-VALUES; both avoid the imperative "return" that seems to imply some kind of throw. I like WITH-VALUES or CALL-WITH-VALUES or CALL-WITH-MULTIPLE-VALUES instead of RECEIVE-VALUES. The problem with "RECEIVE-" is that ones first guess at the meaning of (RECEIVE-VALUES ...) might be that it "receives" multiple values and returns them, rather than disposing of them by a further call. The problem with "CALL-" is that it isn't clear which of the two procedure arguments the "call" refers to. The "CALL-" in CALL-WITH-MULTIPLE-VALUES refers to the second argument. The "CALL-" in CALL-EXPECTING-MULTIPLE-VALUES refers to the first. > Well, here is my argument for proposal #2: > > I think that there is a very important symmetry between procedure > invocation and continuation invocation. Indeed, if the code is CPS > converted, they become the same thing. This symmetry gives us a rational basis for the whole idea, so I like the idea of remaining consistent with it. > [...] > Now, wait a minute... This seems like an argument for #1, right? > > Well, the difference is that there are (as far as I can tell) no > implicit procedures, but there certainly are implicit continuations, > and the behavior can be different. > > The rule is as follows: an implicit continuation may be called with > MORE values than it expects, and these extra values are ignored. Thus > [...] I like the idea of defining implicit continuations to look like (LAMBDA (X . IGNORE) ...)). > As far as continuation objects obtained with CWCC are concerned, they > should accept multiple arguments if the corresponding continuation > accepted multiple values, thus [...] This is what I was trying to accomplish with my proposal. Thanks for clarifying the issue. > Having said all this, I'll also say that I'm afraid that we will not > be able to standardize. JAR feels relatively strongly about proposal > #1, and I think that other people do also. I feel relatively strongly > agains standardizing on the CL standard, since I don't believe in the > random NILs (or #Fs) being created on demand, so I'm therefore opposed > to #3, and I would not be surprised if other people had their own pet > theories. Will's proposal was carefully worded so as to allow us to standardize in #1, #2, or #3 and still allow those of us who want to to make extensions compatible with Common Lisp. I think we should make an effort to agree on names and syntax for multiple values, preferably using alternative #2 (but I'll accept #1 if necessary), because it at least gives us a common base for our extensions. In summary: I like the names VALUES (or MULTIPLE-VALUES) and WITH-VALUES (or CALL-WITH-VALUES or CALL-WITH-MULTIPLE-VALUES). I like the syntax proposed by Will. I prefer alternative #2 but will accept #1 rather than lose the chance to standardize. I see no need for MULTIPLE-VALUE-PROG1 or syntactic sugar like MULTIPLE-VALUE-BIND. Regards, David Bartley  Received: from geneva (TCP 2206400372) by MC.LCS.MIT.EDU 2 Apr 87 02:20:53 EST Received: by GENEVA.AI.MIT.EDU; Wed, 1 Apr 87 22:53:32 est Date: Wed, 1 Apr 87 22:53:32 est From: jinx@GENEVA.AI.MIT.EDU (Guillermo J. Rozas) Message-Id: <8704020353.AA11729@geneva> To: bartley%home%ti-csl.csnet@RELAY.CS.NET Cc: rrrs-authors@MC.LCS.MIT.EDU, Bartley%home%ti-csl.csnet@RELAY.CS.NET In-Reply-To: David Bartley's message of Tue, 31 Mar 87 18:25:03 cst <8704010025.AA08042@home> Subject: multiple return values (LONG) *** Note: this is a relatively long message. *** (1) I agree with ALAN and Jinx that it seems pretty useless to specify a multiple value capability and not go beyond Will's alternative #1. Since I intend to implement Common Lisp on top of Scheme, I will want to extend the essential capability anyway. (Are ALAN and Jinx arguing for #2 or #3?) I like #2. More about this below. (2) In his rationale, Will said "The Common Lisp position would say that when zero values are returned to a continuation that is expecting one value, then the symbol NIL is passed to the continuation." I think we could specify this to be "the false value" or "the empty list" and remain compatible with Common Lisp without having to make the symbol NIL noteworthy in Scheme. I don't like arbitrary values created. Again, more on this below. (3) Will's proposal does not mention CALL-WITH-CURRENT-CONTINUATION. It seems that a continuation object should accept an arbitrary number of arguments if we take alternative #2 or #3. If so, we could define (RETURN-VALUES A B) to be the same as (CALL/CC (LAMBDA (K) (K A B))). No and yes, respectively. Again, see below. (4) It seems to me that the hairiest part of the multiple value "feature" in Common Lisp is MULTIPLE-VALUE-PROG1. Something like this is needed, at least "behind the scenes", if we expect DYNAMIC-WIND (etc.) to pass through multiple values. We could express (MULTIPLE-VALUE-PROG1 A B ...) as (receive-values A (lambda L B ... (apply return-values L))) , but that is pretty expensive. Is this common enough to require standardization so implementors could work on more efficient mechanisms? I think it is worth thinking about, but given that the above is sufficient, I don't think there is a need to standardize. (5) JAR finds the proposed feature "to be pretty unuseable unless there is some syntactically sugared way to use RECEIVE-VALUES." If this is true, I think we must agree on what sugar to add. What's the point of standardizing on something that is too cryptic to be used by anyone? I like T's RECEIVE, which I understand to be defined as (receive . ) ==> (receive-values (lambda () ) (lambda . body>)) The key for me is that is a complete lambda list, possibly containing "optional" and "rest" arguments, and is not just a list of "required" identifiers. This seems more flexible than Common Lisp's MULTIPLE-VALUE-BIND. If we keep the name RECEIVE-VALUES, then the name RECEIVE is ok here, but I would prefer something like MULTIPLE-VALUE-LET. What about MULTIPLE-VALUE-BIND? The syntax is not like LET at all, and it really is similar to the CL construct. (6) Let's get down to brass tacks and argue about names! I'm bothered by the "return" in RETURN-VALUES. As Will pointed out, the name RETURN would be confusing to refugees from other Lisps. However, RETURN-VALUES still seems to imply an exit from the calling procedure. A user might ask whether the procedure (LAMBDA (A B C) (+ A (RETURN-VALUES B) C)) returns the sum of A, B, and C or just B? I think we all intend for RETURN-VALUES to "return" to its caller (the middle of the body), not to that procedure's caller. I suggest renaming RETURN-VALUES to be MULTIPLE-VALUES. Likewise, the "receive" in RECEIVE-VALUES seems strange; I would expect the complementary routine to be SEND-VALUES. How about CALL-WITH-MULTIPLE-VALUES (call/mv?) by analogy with CALL-WITH- CURRENT-CONTINUATION (call/cc)? (I'm not sure if I'm joking!) I don't care much about the names of procedures, but I agree with GLS. What's wrong with VALUES? Another possibility for RECEIVE-VALUES is MULTIPLE-VALUE-COMPOSE, or even, CALL-EXPECTING-MULTIPLE-VALUES. ------------------------------------------------------------------------------ Well, here is my argument for proposal #2: I think that there is a very important symmetry between procedure invocation and continuation invocation. Indeed, if the code is CPS converted, they become the same thing. At apply time there is strict number of arguments checking, although procedures, through optional or rest arguments, may allow a range of numbers of arguments. I think it is important to be consistent here and make continuation invocation be the same. Thus when an explicit continuation is provided (as in the case of RECEIVE-VALUES), the number of arguments (values) should be checked just as strictly. Thus, I think that both (receive-values (lambda () (values 1 2 3)) (lambda (a b) ...)) (receive-values (lambda () (values 1)) (lambda (a b) ...)) should be in error. The CL semantics can easily be implemented on top of this by making the actual procedure passed to RECEIVE-VALUES accept any number of arguments, and then initialize the ones not provided with #f. Implementations can even be more lax since being in error does not mean that one is signalled. Now, wait a minute... This seems like an argument for #1, right? Well, the difference is that there are (as far as I can tell) no implicit procedures, but there certainly are implicit continuations, and the behavior can be different. The rule is as follows: an implicit continuation may be called with MORE values than it expects, and these extra values are ignored. Thus returning zero values to a continuation that expects one should be an error (as opposed to creating a #f), but returning 2 should be valid. This makes all the cases that I'm interested in work, yet allows the error checking when multiple values are explicitely asked for. Thus, assuming that QUOTIENT returns 2 values, (let ((x (quotient (fact 100) (expt 2 23)))) ...) should work, but (receive-values (lambda () (quotient (fact 100) (expt 2 23))) (lambda (x) ...)) should be in error. In case you are wondering, the example with the implicit continuation is equivalent to (receive-values (lambda () (quotient (fact 100) (expt 2 23))) (lambda (x . ignore) ...)) As far as continuation objects obtained with CWCC are concerned, they should accept multiple arguments if the corresponding continuation accepted multiple values, thus (receive-values (lambda () (cwcc (lambda (here) (here 2 3)))) (lambda (x y) (list x y))) should return (2 3), (receive-values (lambda () (cwcc (lambda (here) (here 2 3)))) (lambda (x) x)) should be in error, and (let ((x (cwcc (lambda (here) (here 2 3))))) x) should return 2. Thus the number of arguments that continuations expect is not arbitrary, but it is the case that (return a b c) is equivalent to (cwcc (lambda (k) (k a b c))) Having said all this, I'll also say that I'm afraid that we will not be able to standardize. JAR feels relatively strongly about proposal #1, and I think that other people do also. I feel relatively strongly agains standardizing on the CL standard, since I don't believe in the random NILs (or #Fs) being created on demand, so I'm therefore opposed to #3, and I would not be surprised if other people had their own pet theories.  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 2 Apr 87 00:20:13 EST Date: Wed, 1 Apr 87 21:51:51 EST From: Chris Hanson Subject: multiple return values To: JAR@AI.AI.MIT.EDU cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Tue 31 Mar 87 22:13:26 EST from Jonathan A Rees Message-ID: <177708.870401.CPH@AI.AI.MIT.EDU> Date: Tue, 31 Mar 87 22:13:26 EST From: Jonathan A Rees I would strongly oppose the Common Lisp multiple value semantics. I find it to be very distasteful. If this means that the language has no multiple values primitively, and I have to implement semantics #1 myself using lists or closures or whatever, that's fine with me. If I have many sympathizers then I'd say it appears that we're as deadlocked as we were last time this came up... I think that I agree with JAR... I've just got back from vacation and have not yet read all the mail on this (at 1200 baud, I'll wait for work tomorrow!), but I am very disturbed by the direction this is taking. I don't see a need for a complicated semantics! I'll reply more fully later when I've had a chance to read all of this.  Received: from Think.COM (TCP 1201000006) by MC.LCS.MIT.EDU 1 Apr 87 13:03:52 EST Received: from feuerbach by Think.COM via CHAOS; Wed, 1 Apr 87 12:34:23 EST Date: Wed, 1 Apr 87 12:34 EST From: Guy Steele Subject: multiple return values To: bartley%home%ti-csl.csnet@relay.cs.net, rrrs-authors@mc.lcs.mit.edu Cc: gls@think.com In-Reply-To: <8704010025.AA08042@home> Message-Id: <870401123434.4.GLS@FEUERBACH.THINK.COM> Date: Tue, 31 Mar 87 18:25:03 cst From: David Bartley ... (6) Let's get down to brass tacks and argue about names! I'm bothered by the "return" in RETURN-VALUES. As Will pointed out, the name RETURN would be confusing to refugees from other Lisps. However, RETURN-VALUES still seems to imply an exit from the calling procedure. A user might ask whether the procedure (LAMBDA (A B C) (+ A (RETURN-VALUES B) C)) returns the sum of A, B, and C or just B? I think we all intend for RETURN-VALUES to "return" to its caller (the middle of the body), not to that procedure's caller. I suggest renaming RETURN-VALUES to be MULTIPLE-VALUES. ... Actually, I think this is one of the few names that Common Lisp really got right. What's wrong with VALUES? Note that it is likely to be used much more frequently than the matching receiving form. --Guy  Received: from geneva (TCP 20015013114) by MC.LCS.MIT.EDU 1 Apr 87 08:49:46 EST Received: by ; Wed, 1 Apr 87 08:48:04 est Date: Wed, 1 Apr 87 08:48:04 est From: kwh@@ (Ken Haase) Message-Id: <8704011348.AA08026@geneva> To: JAR@AI.AI.MIT.EDU Cc: rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees's message of Tue, 31 Mar 87 22:13:26 EST <177055.870331.JAR@AI.AI.MIT.EDU> Subject: multiple return values I do the same thing, having a set of `PLUS' files which extend R^*S in implementation dependent ways to provide features I want to use. One thing that I've found useful in transporting code between Common LISP implementations (or Symbolics LISP releases!) has been a standard way (the STATUS form) for determining what system or release I'm in. Beyond this, though I find it somewhat distasteful, the presence of the `#+' character macro for read-time conditionalizing code makes writing transportable code a good deal easier. Ken  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 31 Mar 87 23:23:05 EST Date: Tue, 31 Mar 87 22:17:54 EST From: Jonathan A Rees Subject: multiple return values To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Tue 31 Mar 87 18:25:03 cst from David Bartley Message-ID: <177057.870331.JAR@AI.AI.MIT.EDU> Date: Tue, 31 Mar 87 18:25:03 cst From: David Bartley Likewise, the "receive" in RECEIVE-VALUES seems strange; I would expect the complementary routine to be SEND-VALUES. How about CALL-WITH-MULTIPLE-VALUES (call/mv?) by analogy with CALL-WITH- CURRENT-CONTINUATION (call/cc)? (I'm not sure if I'm joking!) How about CALL-CURRENT-CONTINUATION ? A little long I guess... I don't much like the Unix command names (mv, cc)... SEND-VALUES isn't so bad. PROVIDE-VALUES, GIVE-VALUES ACCEPT-VALUES, USE-VALUES, TAKE-VALUES, GET-VALUES  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 31 Mar 87 23:02:38 EST Date: Tue, 31 Mar 87 22:13:26 EST From: Jonathan A Rees Subject: multiple return values To: bartley%home%ti-csl.csnet@RELAY.CS.NET cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of Tue 31 Mar 87 18:25:03 cst from David Bartley Message-ID: <177055.870331.JAR@AI.AI.MIT.EDU> I would strongly oppose the Common Lisp multiple value semantics. I find it to be very distasteful. If this means that the language has no multiple values primitively, and I have to implement semantics #1 myself using lists or closures or whatever, that's fine with me. If I have many sympathizers then I'd say it appears that we're as deadlocked as we were last time this came up... There's a deeper issue here: I have found that I use a number of features which can be implemented easily enough in Scheme, but for which particular scheme implementations have efficient, low-level, nonstandard support. For example: multiple values, fixnum arithmetic, byte vectors, certain string operations (like what was in the R^2 report), hash tables, PEEK-CHAR, and bitwise logical opertions. What I do is I have one particular file which implements all these features portably. I can then replace this file for particular implementations to get better performance. In general I'll have N+1 versions of this file, one portable version plus one version for each implementation for which it's been tuned. Does anyone else do things like this? Or am I the only person who really tries to write nontrivial programs that are both portable and fast? The fact that my programs are portable, and that this "tuning file" is small in size, is of course due to our standardization effort. It's not clear that implementation-dependent tuning can go away completely, but the smaller that file is, the happier I'll be. This is the main argument I see for adding logically redundant features (like multiple values #1) to the standard; I assume that's why LENGTH and MEMQ are in the report. Maybe we need a better way to organize these redundant features; they don't really belong in the main part of the report. Jonathan  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 31 Mar 87 21:14:11 EST Received: from relay2.cs.net by RELAY.CS.NET id ag22435; 31 Mar 87 20:42 EST Received: from ti-csl by RELAY.CS.NET id ar06470; 31 Mar 87 20:35 EST Received: from home (home.ARPA) by tilde id AA22798; Tue, 31 Mar 87 18:25:08 cst Received: by home id AA08042; Tue, 31 Mar 87 18:25:03 cst Date: Tue, 31 Mar 87 18:25:03 cst From: David Bartley Message-Id: <8704010025.AA08042@home> To: rrrs-authors@MC.LCS.MIT.EDU Cc: Bartley%home%ti-csl.csnet@RELAY.CS.NET Subject: multiple return values (1) I agree with ALAN and Jinx that it seems pretty useless to specify a multiple value capability and not go beyond Will's alternative #1. Since I intend to implement Common Lisp on top of Scheme, I will want to extend the essential capability anyway. (Are ALAN and Jinx arguing for #2 or #3?) (2) In his rationale, Will said "The Common Lisp position would say that when zero values are returned to a continuation that is expecting one value, then the symbol NIL is passed to the continuation." I think we could specify this to be "the false value" or "the empty list" and remain compatible with Common Lisp without having to make the symbol NIL noteworthy in Scheme. (3) Will's proposal does not mention CALL-WITH-CURRENT-CONTINUATION. It seems that a continuation object should accept an arbitrary number of arguments if we take alternative #2 or #3. If so, we could define (RETURN-VALUES A B) to be the same as (CALL/CC (LAMBDA (K) (K A B))). (4) It seems to me that the hairiest part of the multiple value "feature" in Common Lisp is MULTIPLE-VALUE-PROG1. Something like this is needed, at least "behind the scenes", if we expect DYNAMIC-WIND (etc.) to pass through multiple values. We could express (MULTIPLE-VALUE-PROG1 A B ...) as (receive-values A (lambda L B ... (apply return-values L))) , but that is pretty expensive. Is this common enough to require standardization so implementors could work on more efficient mechanisms? (5) JAR finds the proposed feature "to be pretty unuseable unless there is some syntactically sugared way to use RECEIVE-VALUES." If this is true, I think we must agree on what sugar to add. What's the point of standardizing on something that is too cryptic to be used by anyone? I like T's RECEIVE, which I understand to be defined as (receive . ) ==> (receive-values (lambda () ) (lambda . body>)) The key for me is that is a complete lambda list, possibly containing "optional" and "rest" arguments, and is not just a list of "required" identifiers. This seems more flexible than Common Lisp's MULTIPLE-VALUE-BIND. If we keep the name RECEIVE-VALUES, then the name RECEIVE is ok here, but I would prefer something like MULTIPLE-VALUE-LET. (6) Let's get down to brass tacks and argue about names! I'm bothered by the "return" in RETURN-VALUES. As Will pointed out, the name RETURN would be confusing to refugees from other Lisps. However, RETURN-VALUES still seems to imply an exit from the calling procedure. A user might ask whether the procedure (LAMBDA (A B C) (+ A (RETURN-VALUES B) C)) returns the sum of A, B, and C or just B? I think we all intend for RETURN-VALUES to "return" to its caller (the middle of the body), not to that procedure's caller. I suggest renaming RETURN-VALUES to be MULTIPLE-VALUES. Likewise, the "receive" in RECEIVE-VALUES seems strange; I would expect the complementary routine to be SEND-VALUES. How about CALL-WITH-MULTIPLE-VALUES (call/mv?) by analogy with CALL-WITH- CURRENT-CONTINUATION (call/cc)? (I'm not sure if I'm joking!) Regards, David Bartley  Received: from mitre-bedford.ARPA (TCP 3200600102) by MC.LCS.MIT.EDU 31 Mar 87 19:03:33 EST Posted-From: The MITRE Corp., Bedford, MA Received: by faron.MENET (4.12/4.7) id AA11841; Tue, 31 Mar 87 15:36:20 est Date: Tue, 31 Mar 87 15:36:20 est From: John D. Ramsdell Posted-Date: Tue, 31 Mar 87 15:36:20 est Message-Id: <8703312036.AA11841@faron.MENET> To: rrrs-authors%mc.lcs.mit.edu@mitre-bedford.ARPA Subject: Scheme Numbers Last night I tried to find out where the R^3RS disallows the reordering of computation involving inexact numbers. Numerical analysts know that floating point addition and multiplication are not commutative, and write code that depends on the fact that these operation are to be preformed in the precise order given. One of the things FORTRAN does correctly is promise not to reorder computations involving inexact numbers. I never found that promise last night. Let's make that promise to Scheme users in R^4RS. John  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 30 Mar 87 23:31:07 EST Received: from relay2.cs.net by RELAY.CS.NET id ae29609; 30 Mar 87 22:44 EST Received: from tektronix.tek.com by RELAY.CS.NET id ac00188; 30 Mar 87 22:40 EST Received: by tektronix.TEK.COM (5.51/6.20) id AA10175; Mon, 30 Mar 87 13:58:25 PST Received: by tekchips.TEK.COM (5.31/6.19) id AA06188; Mon, 30 Mar 87 13:56:53 PST Date: Mon, 30 Mar 87 13:56:53 PST From: Norman Adams Message-Id: <8703302156.AA06188@tekchips.TEK.COM> Subject: Re: multiple return values To: Jonathan A Rees Cc: rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees , Sat, 28 Mar 87 00:03:12 EST If "wrong" doesn't imply "signals an error" then the following is a correct implementation of alternative 1. This is pretty much how the feature was implemented in T2. (define values-marker (list 'values-marker)) (define receive-values (lambda (thunk proc) (let ((vals (thunk))) (if (and (pair? vals) (eq? (car vals) values-marker)) (apply proc (cdr vals)) (proc vals))))) (define return-values (lambda vals (cons values-marker vals))) Not quite a correct implementation, I think. RETURN-VALUES should canonicalize single return values: (define return-values (lambda vals (if (and (pair? vals) (null? (cdr vals))) (car vals) (cons values-marker vals)))) -Norman -------  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 30 Mar 87 21:58:15 EST Date: Mon, 30 Mar 87 21:39:51 EST From: Jonathan A Rees Subject: Let's get together again To: willc%tekchips.tek.com@RELAY.CS.NET cc: RRRS-Authors@MC.LCS.MIT.EDU In-reply-to: Msg of 30 Mar 87 10:53:22 PST (Mon) from willc%tekchips.tek.com at RELAY.CS.NET Message-ID: <176355.870330.JAR@AI.AI.MIT.EDU> I think it's a great idea. If no one else from MIT wants to do local arrangements I'd be happy to.  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 30 Mar 87 17:38:45 EST Received: from relay2.cs.net by RELAY.CS.NET id ab22416; 30 Mar 87 15:49 EST Received: from tektronix.tek.com by RELAY.CS.NET id aj28003; 30 Mar 87 15:41 EST Received: by tektronix.TEK.COM (5.51/6.20) id AA07158; Mon, 30 Mar 87 10:54:59 PST Received: by tekchips.TEK.COM (5.31/6.19) id AA03755; Mon, 30 Mar 87 10:53:26 PST Message-Id: <8703301853.AA03755@tekchips.TEK.COM> To: RRRS-Authors@MC.LCS.MIT.EDU, willc%tekchips.tek.com@RELAY.CS.NET Cc: KMP@SCRC-STONY-BROOK.ARPA, jinx%geneva.ai.mit.edu@RELAY.CS.NET Subject: Re: Let's get together again In-Reply-To: Your message of Sat, 28 Mar 87 16:11:21 est. <8703282111.AA05557@geneva> Date: 30 Mar 87 10:53:22 PST (Mon) From: willc%tekchips.tek.com@RELAY.CS.NET 27-28 June (Saturday and Sunday) is fine with me. The person in charge of local arrangements probably ought to be the one to decide the dates as well. Any volunteers? Norman Adams pointed out to me that Jonathan's implementation of multiple return values (as in equation 1 for "single") can be patched quite easily---he'll be posting the patch. The ease of implementing equation 1 in existing implementations must then make it my favorite too. Peace, Will  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 30 Mar 87 17:33:22 EST Received: from relay2.cs.net by RELAY.CS.NET id ac22144; 30 Mar 87 15:43 EST Received: from tektronix.tek.com by RELAY.CS.NET id af28003; 30 Mar 87 15:39 EST Received: by tektronix.TEK.COM (5.51/6.20) id AA03473; Mon, 30 Mar 87 09:24:47 PST Received: by tekchips.TEK.COM (5.31/6.19) id AA02271; Mon, 30 Mar 87 09:23:19 PST Message-Id: <8703301723.AA02271@tekchips.TEK.COM> To: JAR@MC.LCS.MIT.EDU Cc: rrrs-authors@MC.LCS.MIT.EDU Subject: Re: multiple return values In-Reply-To: Your message of Sat, 28 Mar 87 00:03:12 EST. <174983.870328.JAR@AI.AI.MIT.EDU> Date: 30 Mar 87 09:23:17 PST (Mon) From: willc%tekchips.tek.com@RELAY.CS.NET Will: I see no way to implement the proposed procedures in R3RS Scheme, but most implementations should find it easy to add them. Jonathan: If "wrong" doesn't imply "signals an error" then the following is a correct implementation of alternative 1. This is pretty much how the feature was implemented in T2.... Unfortunately, Jonathan's simple implementation of receive-values and return-values doesn't quite work: (list 1 (return-values 2) 3) is supposed to evaluate to (1 2 3) but with Jonathan's implementation it evaluates to (1 (values-marker 2) 3). The problem is that RETURN-VALUES doesn't know whether it is returning to a continuation created by RECEIVE-VALUES or to an "ordinary" continuation. The simplest correct implementations I've been able to imagine require that one machine instruction be added to the standard continuation invocation sequence (i.e. returns from closed-coded non-tail-recursive calls). Peace, Will  Received: from geneva (TCP 2206400372) by MC.LCS.MIT.EDU 30 Mar 87 13:08:03 EST Received: by GENEVA.AI.MIT.EDU; Mon, 30 Mar 87 13:04:33 est Date: Mon, 30 Mar 87 13:04:33 est From: jinx@GENEVA.AI.MIT.EDU (Guillermo J. Rozas) Message-Id: <8703301804.AA09557@geneva> To: JAR@AI.AI.MIT.EDU Cc: rrrs-authors@MC.LCS.MIT.EDU In-Reply-To: Jonathan A Rees's message of Mon, 30 Mar 87 12:20:13 EST <175971.870330.JAR@AI.AI.MIT.EDU> Subject: [ALAN: multiple return values] I agree with ALAN here. I used to prefer the stricter semantics, but after some thought I've arrived at the conclusion that it is silly. It adds no new functionality and is hardly more convenient than passing an explicit continuation (syntax for which can be provided). The case I like to consider is the case of QUOTIENT (there are many others like it). It is often very cheap (or even necessary) to produce the remainder of an integer division when computing the quotient. Thus it would be natural for QUOTIENT to return the remainder as a second value. The strict semantics would force anyone using quotient to use RECEIVE-VALUES, although a very common use, in fact, is to ignore the remainder. In the absence of "loose" multiple values, there are two possibilities, both distasteful: - Provide another procedure which returns both (as in the case of MIT Scheme's INTEGER-DIVIDE), but this tends to increase the number of procedures that users have to know about to an unreasonable extent. - Force users to use both QUOTIENT and REMAINDER when both results are desired. The only way to get efficiency out of this one is to fall into the "mighty compiler" assumption. I think, therefore, that it would not be a good idea to agree on a standard that allows the strict semantics (and I would vote against it). If some people have serious objections to the "loose" semantics, then we may be better off not standardizing at all.  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 30 Mar 87 12:23:13 EST Date: Mon, 30 Mar 87 12:20:13 EST From: Jonathan A Rees Subject: [ALAN: multiple return values] To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <175971.870330.JAR@AI.AI.MIT.EDU> Date: Sun, 29 Mar 87 02:29:12 EST From: Alan Bawden To: JAR at AI.AI.MIT.EDU Re: multiple return values I will confine myself to reminding you of what I said the last time this subject was raised: Any implementation of multiple-values that doesn't have the property that ordinary continuations (for example the continuation passed to F in (+ (F) 3)) will accept and ignore extra values has missed the point of multiple values. Let me try putting it another way: If you decide on a semantics for multiple values that has the property that a correct implementation can be written in straight R^3RS Scheme, then what have you accomplished? You haven't given the users anything they couldn't have written for themselves. (Yes, perhaps you can arrange to implement it more efficiently, but since when has that been the the spirit of the language?)  Received: from OZ.AI.MIT.EDU by MC.LCS.MIT.EDU via Chaosnet; 29 MAR 87 19:04:10 EST Date: Sun 29 Mar 87 18:57:57-EST From: "Gerald Jay Sussman" Subject: meeting To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <12290358923.7.GJS@OZ.AI.MIT.EDU> I agree with Will. I think we should meet and get things under control. -------  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 28 Mar 87 23:28:18 EST Date: Sat, 28 Mar 87 23:24:42 EST From: Jonathan A Rees Subject: a modest macro proposal To: rrrs-authors@MC.LCS.MIT.EDU Message-ID: <175356.870328.JAR@AI.AI.MIT.EDU> Macros for Scheme Jonathan Rees 28 March 1987 Primary objectives: - Macros are scoped, so users won't step on each others' toes. - The client of a macro need not know anything about the macro's implementation. In particular, capture problems must be avoidable both for syntactic keywords and variables. Secondary objectives: - Consistent with the "expansion passing style" described in [1]. - Consistent with the spirit of the macro facilities provided by MIT Scheme and T. This is a rough draft, and contains more questions than answers, but I want to get feedback, and answers to the questions, so here it is. Overview: 1. Fundamental mechanism Describes the basic ideas of syntax tables and preprocessed expressions. 2. Defining macros Describes two new expression types that introduce scoped macro definitions. 3. Avoiding free variable capture Describes ways to circumvent capture problems. 4. Convenience features Discusses higher-level layers that could make macro writing easier. 5. Notes and questions Appendix. An implementation 1. Fundamental mechanism Two abstractions are introduced, "syntax table" and "preprocessed expression". A "syntax table" describes a particular mapping from concrete syntax (expressions) to abstract syntax (preprocessed expressions). When a user defines a macro, he implicitly defines a variant on the language and therefore a new mapping from expressions to preprocessed expressions. 1.1. Reference guide (For the purposes of this discussion, the term "expression" means "s-expression", or more precisely: - Symbols, numbers, booleans, characters, strings, and empty lists are expressions. - If E1 and E2 are expressions then the pair (E1 . E2) is an expression. (In particular, lists of expressions are expressions.) - If E0, ... En are expressions, then the vector #(E1 ... En) is an expression. - A preprocessed expression is an expression. - There are no other expressions.) (PREPROCESS expression syntax-table) PREPROCESS preprocesses expression according to syntax-table, and returns a preprocessed expression. The manner in which the preprocessed expression is determined depends entirely on the syntax table argument (see the various ways to create syntax tables, below), with the following exception: (PREPROCESS p syntax-table) always returns p if p is already a preprocessed expression. It is an error if expression is not syntactically valid according to syntax-table. SCHEME-SYNTAX-TABLE The value of SCHEME-SYNTAX-TABLE is a syntax table that corresponds to a language conforming to the Revised^3 Report. In gory detail, this means: let E be an expression, and let P be the preprocessed expression that results from calling (PREPROCESS E SCHEME-SYNTAX-TABLE). - If E is a number, boolean, string, or character, then P denotes an appropriate literal expression. - If E is a symbol, and E is not a Scheme syntactic keyword (QUOTE, LAMBDA, etc.), then P denotes a variable reference. - If E is a pair whose car is a syntactic keyword, then P denotes an appriopriate expression (unless it contins a syntax error). - If E is a nonempty list whose car is an expression, then P denotes a combination (unless some subexpression contains a syntax error). - If E is already a preprocessed expression, E is equal to P. - Otherwise E is not syntactically valid. (ADD-KEYWORD syntax-table symbol expansion-proc) Expansion-proc must be a procedure of two arguments, an expression and a syntax table. Expansion-proc must return a preprocessed expression. ADD-KEYWORD returns a new syntax table according to which expressions of the form (symbol ...) are preprocessed by expansion-proc. That is, PREPROCESS will call expansion-proc and return what it returns. The arguments passed to expansion-proc will be the expression and syntax-table that were passed to PREPROCESS. Any other expression E is preprocessed the same way it would have been preprocessed according to syntax-table. If this means that it is to be preprocessed according to SCHEME-SYNTAX-TABLE, then any subexpressions of the expression will be preprocessed according to the syntax table that was originally passed to PREPROCESS, not according to SCHEME-SYNTAX-TABLE. (REMOVE-KEYWORD syntax-table symbol) This returns a syntax table in which an expression of the form (symbol ...) denotes a combination. If symbol had an associated expansion procedure in syntax-table, that expansion procedure will be ignored in the new syntax table. 1.2. Discussion The following may be a helpful analogy: (EVAL (PREPROCESS lambda-expression expression environment) syntax-table) => closure => preprocessed-expression EVAL (or the ENCLOSE of the Revised Report) takes a lambda-expression, which is context-dependent or "open" because it contains free variables, and turns it into something that's context-independent or "closed", namely a closure. PREPROCESS takes an expression, which is context-dependent because the meanings of subexpressions depend on what macros are in effect, and returns something that is context-independent and therefore immune to the vagaries of the macro context into which it may be placed. Preprocessed expressions may legitimately appear as subexpressions of expressions to be passed to PREPROCESS. For example, if M1 and M2 are preprocessed-expressions, then `(AND ,M1 ,M2) is a valid expression that can be passed again to PREPROCESS (assuming AND has its usual meaning). The effect of this is the same as if the expression had been an AND-expression whose subexpressions were expressions that would have been preprocessed as M1 and M2 in whatever syntax-table was the second argument to the call to PREPROCESS. The nature of "preprocessed-expression" objects is not specified here; they may or may not be lists, vectors, procedures, etc., or objects of some new data type. This proposal does not provide any explicit operations on preprocessed expressions, but it doesn't preclude such operations, either. Presumably LOAD, EVAL, and compilers know how to manipulate preprocessed-expressions. Similarly, there may be operations on syntax tables other than the ones given here; in particular the clever tricks in [1] could easily work in this framework. Note that the syntax table passed to an expansion procedure is not necessarily the same as the syntax table returned by the call to ADD-KEYWORD that defined its keyword. The syntax table is the appropriate one to use in processing subexpressions. The syntax table argument serves the same purpose as the expansion procedure passed to expanders in [1]. Detail: definitions, as well as expressions, may be passed to PREPROCESS. 1.3. Examples Example 1: The following evaluates to a syntax table that is the same as that for R^3R Scheme except that FOO is a syntactic keyword and (FOO x) means the same as (QUOTE x). (add-keyword scheme-syntax-table 'foo (lambda (e st) (preprocess `(quote ,(cadr e)) scheme-syntax-table))) This illustrates the general principle that a more complicated syntax-table can be defined in terms of a simpler one. An expression E written in a more complicated language L (not even known at macro definition time) is transformed into a new expression (the expansion), and then the preprocessed version of the new expression is determined according to a syntax-table that is known by the expansion procedure to support the QUOTE keyword in the expected way. Example 2: The following procedure will augment a given syntax table with a definition of a simple LET macro. (define (add-let st) (add-keyword st 'let (lambda (exp st) (let ((bindings (cadr exp)) (body (cddr exp))) (preprocess `((lambda ,(map car bindings) ,@(map (lambda (exp) (preprocess exp st)) body)) ,@(map (lambda (binding) (preprocess (cadr binding) st)) bindings)) scheme-syntax-table))))) The fact that preprocessed-expressions act like normal forms permits the use of ordinary list constructors (like backquote) in constructing partially preprocessed expressions. Note that PREPROCESS is used within expansion procedures for two distinct purposes: (a) To compute a preprocessed expression, in the current syntax table, for each sub-expressions of the expression being expanded. (b) To preprocess, according to some known syntax table, an expression that has been determined to be equivalent to the original expression. Why are syntax tables immutable? This aids (but doesn't guarantee) consistency between compiled and interpreted code. 2. Defining macros 2.1. LET-SYNTAX (LET-SYNTAX (((keyword exp-var st-var) . expansion) ...) . body) LET-SYNTAX is used to define a macro that is local to a single expression (in practice it is often wrapped around most of a file). (T and MIT Scheme both have constructs like this.) For example, (let-syntax (((foo exp st) (preprocess `(quote ,(cadr exp)) scheme-syntax-table))) (foo (a b c))) => (a b c) LET-SYNTAX need not be primitive, assuming there exists an EVAL procedure and some environment EXPANDER-ENV in which to close expansion procedures. The following adds a LET-SYNTAX expression type to any syntax table S: (add-keyword S 'let-syntax (lambda (exp st) (do ((specs (cadr exp) (cdr specs)) (st st (let ((spec (car specs))) (add-keyword st (caar spec) (eval `(lambda ,(cdar spec) ,@(cdr spec)) expander-env))))) ((null? specs) (preprocess `(begin ,@(map (lambda (exp) (preprocess exp st)) (cddr exp))) scheme-syntax-table))))) In order to reduce the possibility that a macro could accidentally or intentionally depend on some run-time binding, it is strongly advised to make the environment in which expanders are closed be disjoint from the environment in which the expanded code will be run. Otherwise one could find oneself in the embarrasssing situation of having code that "works" in an incrementally compiled implementation but not in a block- or cross-compiled implementation. 2.2. USING-SYNTAX (USING-SYNTAX syntax-table-exp . body) USING-SYNTAX lets one make use of some specific macro environment. (using-syntax scheme-syntax-table (quote yow)) => yow (add-keyword syntax-table 'using-syntax (lambda (exp syntax-table) ;; ignore syntax-table (let ((syntax-table (eval (cadr exp) expander-env))) (preprocess `(begin ,@(map (lambda (exp) (preprocess exp syntax-table)) (cddr exp))) scheme-syntax-table)))) Subtle point: For these two forms, it might make just as much sense, and perhaps more, to say (eval (preprocess foo syntax-table) expander-env) as (eval foo expander-env) -- i.e. macros can be written using the macros in effect where the text of the macro definition occurs, even if they can't make use of the lexical environment. 3. Avoiding free variable capture 3.1. Free variables introduced into expansions We want to be able to do things like (let ((cons +)) `(a ,(cons 1 2) b)) and not lose when QUASIQUOTE expanding into a call to CONS. It doesn't work to write (as Dan Friedman and others have suggested) `(',car ,z) in the definition of QUASIQUOTE because this presents horrible questions about the meaning of cross-compilation that no one is prepared to answer right now. Kohlbecker's solution amounts to performing alpha-conversion and macro expansion at the same time. This is a lot of mechanism and breaks down in a few places. Here is a much simpler, low-tech solution. The solution is for the expander to introduce special expressions into the expansion that represent "absolute" or "global" references. Such references are not sensitive to the lexical environment. (ABSOLUTE node1 node2 ...) [syntax] Finds a value in an implementation-dependent, tree-structured namespace. Each node_i should be an identifier; this is to be considered analogous to a Multics-style pathname >node1>node2>.... In order to make it as easy as possible, Scheme implementors are urged to cooperate in apportioning sections of this namespace so that there no conflicts can arise. This is an aministrative problem analgous to domain naming on the Internet, and perhaps solvable by similar means. Only one portion of the namespace is defined here, namely that the top-level SCHEME-ENV node has as subnodes all the names in the initial R^3R Scheme environment. E.g. (let ((+ -)) ((absolute scheme-env +) 1 2)) => 3 (Note that ABSOLUTE must be a new kind of expression -- a procedure can't so the trick, since that would beg the question of how to name THAT procedure.) 3.2. Bound variables introduced into the expansion The flip side of this problem is that macros often want to introduce new bound variables into expansions, and we don't want these names to accidentally conflict with names already used in the client's code. Common Lisp (Maclisp, etc.) programmers don't consider this to be a problem, since GENSYM and GENTEMP exist. T has GENERATE-SYMBOL (?) and MIT Scheme has GENERATE-UNINTERNED-SYMBOL. I think something like this would do the trick. However, I would very much like to preserve the invariant (EQ? SYM (STRING->SYMBOL (SYMBOL->STRING SYM))). which is violated by GENSYM (and GENERATE-UNINTERNED-SYMBOL). One solution, with a well-defined semantics, would be to have a procedure that returns a symbol not ocurring in a given expression (or expressions): (SYMBOL-NOT-OCCURRING-IN exp) => symbol This has a nice functional flavor to it, but it could be implemented nondeterministically, in such a way that only the symbol table need be examined, not exp itself. (I think T3 does this.) Another possibility would be to apportion some subset of the set of all symbols for use as "unique identifiers", e.g. all symbols starting with some "obscure" prefix, not necessarily even readable (although read/print symmetry is also a nice feature...). I don't want to make a concrete proposal at this time. 4. Convenience features Writing correct macros using ADD-KEYWORD is possible, but cumbersome and error prone. One must remember to call PREPROCESS on sub-expressions and on the final output, passing the correct syntax table to each. There are several possible ways to address this problem. One is to say that we should not be in the business of making it easy to write macros, but instead should do what we can to discourage users from writing macros, or at least make them recognize the pitfalls. In this view, the complexity of the process is good. A second solution is Kohlbecker's "hygienic expansion", which makes it easy to write correct macros. I suspect this mechanism could be implemented in terms of the low-level primitives given above, but I think it has some drawbacks; there are many useful kinds of macros that can't be written. I am working on a third solution that, loosely speaking, makes use of a syntactic description (BNF-like) of the expression type in order to preprocess subexpressions before handing them to the expansion procedure. The result is more verbose than hygienic macros and only a little more verbose than Common Lisp's macros. 5. Notes and open questions 5.1. Compatibility notes T and MIT Scheme already have syntax tables, but they're mutable. Expansion procedures are called "syntax descriptors" in T. T has a MACRO-EXPANDER macro that creates expansion procedures. MIT Scheme has a MACRO macro for the same purpose. In MIT Scheme, the syntax table is passed implicitly as a fluid-bound variable. In T, it is possible to get at the syntax table, as an extra argument to an expander, but it's painful. In Common Lisp, the syntax-table corresponds roughly to the &environment argument to macros (except that in CL you are forbidden to redefine a special form -- this proposal permits that). PREPROCESS is similar to the SYNTAX procedure in MIT Scheme, and vaguely similar to STANDARD-COMPILER in T. ABSOLUTE is similar to MIT Scheme's ACCESS. In ACCESS, the last subform is evaluated, which isn't quite what we want, since that makes it context-sensitive again (although this greatly reduces opportunities for lossage). [Also, I find the argument order to ACCESS confusing; it's backwards from the way filenames are usually written (on Multics and Unix at least) and also backwards from things like VECTOR-REF, where the aggregate or superior object comes first.] 5.2. Syntax table used by LOAD and/or command loop 1. Which syntax table is used to process forms read by LOAD? 2. Which syntax table is used to process forms typed at a read-eval-print loop? 3. How can one perform definitions in the environment that will be seen by USING-SYNTAX? Here is one conservative proposal, although there are many possibilities and variations: The top level syntax-table for any file is initially SCHEME-SYNTAX-TABLE. Changes must be made explicitly via USING-SYNTAX or LET-SYNTAX, which should be wrapped around the enire file if necessary. The syntax table used at the read-eval-print loop is changed in some implementation-dependent manner (there's nothing that even says there IS a read-eval-print loop). E.g. there could be a procedure (SET-CURRENT-SYNTAX-TABLE! syntax-table). 5.3. Keywords and variables Several people have complained that (let ((if list)) (if 1 2 3)) ought, according to the rules of lexical scope, to evaluate to (1 2 3). It is possible in this framework to make syntax-tables in which variable bindings shadow syntax bindings, but it requires cooperation from every macro that binds variables (LET, LETREC, LAMBDA, etc.): (add-syntax foo 'lambda (lambda (exp st) ... (do ((vars vars (cdr vars)) (st st (remove-syntax (car vars) st))) ...) ...)) I'd rather not raise this question here since it's really orthogonal to the rest of this proposal. 5.4. Macros that expand into multiple definitions The syntax of should be extended to include sequence expressions: --> * --> | | (begin +) This is so that macros at top level can expand into multiple definitions: (begin (define foo ...) (define bar ...)). There is an ambiguity here in that (begin +) can be parsed in either of two ways, but the meaning is the same in either case, so this isn't a grave problem. Should the syntax of a be similarly extended to allow expansions like (lambda (...) (begin (define ...) (define ...)) ...)? What about (lambda (...) (begin (define ...) (compute ...)) ...)? What about (lambda (...) (begin (compute ...) (define ...)) ...)? 5.5. Delayed expansion Some implementations may want to delay macro expansion (preprocessing) so that the expression tree is processed breadth-first instead of depth-first. This could be handy for any number of purposes, e.g. in preventing propagation of syntax errors, in performing alpha-conversion in parallel with macro expansion, or to speed up file loading. This should be explicitly permitted by the proposal. The only way it would make a difference is if a macro expander could observe or perform a side-effect. 5.6. Analysis of subexpressions I think it's a bad idea for macros to go snooping into their subexpressions. This should be unnecessary for "optimization" (the main reason people did this in Maclisp); it's hard to come up with valid reasons to want to do it. On the other hand, it would be nice if someone writing a compiler could portably use PREPROCESS as a front end. This would mandate having operations for decomposing preprocessed expressions. One possibility would be to define a set of accessors and predicates, as MIT Scheme does. Another way to do it would be to have one or more coercion functions to do the inverse of PREPROCESS, e.g. (UNPREPROCESS p-e) would return an expression e such that (PREPROCESS e SCHEME-SYNTAX-TABLE) would return something equivalent to p-e; then one could use CAR and CDR to take the result apart. Either way you have to answer sticky questions, however, such as whether derived expressions like LETREC should be expanded out or preserved. 5.7. Other ways to manipulate the keyword/expander association Maybe we also want MOVE-KEYWORD or RENAME-KEYWORD? References. [1] Dybvig, Friedman, and Haynes. Expansion-passing style: Beyond conventional macros. 1986 ACM Lisp & FP Conference. [2] Kohlbecker's thesis. [3] T manual. [4] Common Lisp. [5] Revised^3 Scheme Report. --------------------- Appendix: a rudimentary implementation. ;;; Preprocessed expressions (define (preprocessed? obj) (and (vector? obj) (= (vector-length obj) 2) (eq? (vector-ref obj 0) 'preprocessed))) (define (make-preprocessed core-exp) (if (preprocessed? core-exp) core-exp (vector 'preprocessed core-exp))) ;;; ->CORE translates a preprocessed expression into the core language. (define (->core exp) (if (preprocessed? exp) (vector-ref exp 1) (error "not a preprocessed expression" exp))) ;;; A syntax table is a procedure, and PREPROCESS is FUNCALL. (define (preprocess exp st) (st exp st)) (define (add-keyword st0 keyword proc) (lambda (exp st) (if (and (pair? exp) (eq? (car exp) keyword)) (proc exp st) (st0 exp st)))) ;;; An empty syntax table; defines no special expression types. (define empty-syntax-table (lambda (exp st) (cond ((symbol? exp) (make-preprocessed exp)) ((or (boolean? exp) (number? exp) (char? exp) (string? exp)) (make-preprocessed exp)) ((preprocessed? exp) exp) ;Idempotent! ((not (pair? exp)) (error "not a syntactically valid expression" exp)) (else ;; Combination ;; (There is a small bug here if REMOVE-KEYWORD exists) (make-preprocessed (map (lambda (arg) (->core (preprocess arg st))) exp)))))) ;;; Core syntax table. Understands the primitive expression types, but ;;; not the derived ones. (define core-syntax-table (do ((st empty-syntax-table (add-keyword st (caar z) (cadar z))) (z `((quote ,(lambda (exp st) (make-preprocessed exp))) (lambda ,(lambda (exp st) (make-preprocessed `(lambda ,(cadr exp) ,(->core (preprocess (caddr exp) st)))))) (set! ,(lambda (exp st) (make-preprocessed `(set! ,(cadr exp) ,(->core (preprocess (caddr exp) st)))))) (define ,(lambda (exp st) (make-preprocessed `(define ,(cadr exp) ,(->core (preprocess (caddr exp) st)))))) (if ,(lambda (exp st) (make-preprocessed `(if ,(->core (preprocess (cadr exp) st)) ,(->core (preprocess (caddr exp) st)) ,(->core (preprocess (cadddr exp) st)))))) (begin ,(lambda (exp st) (make-preprocessed `(begin ,@(map (lambda (exp) (->core (preprocess exp st))) (cdr exp)))))) (absolute ,(lambda (exp st) (make-preprocessed exp)))) (cdr z))) ((null? z) st))) ;;; The scheme syntax table defines the derived expression types. (define scheme-syntax-table (do ((st core-syntax-table (add-keyword st (caar z) (cadar z))) (z `((and ,(lambda (exp st) (let ((forms (cdr exp)) (j (lambda (exp) (preprocess exp st)))) (cond ((null? forms) `#t) ((null? (cdr forms)) (j (car forms))) (else (preprocess `((lambda (p th) (if p (th) p)) ,(car forms) (lambda () (and ,@(map j (cdr forms))))) scheme-syntax-table)))))) ;; ... (lambda ,(lambda (exp st) (preprocess `(lambda ,(cadr exp) ,(preprocess-body (cddr exp) st)) core-syntax-table))) ;; (letrec ,...) ;; ... ;; (quasiquote ,... (absolute scheme-env cons) ...) ) (cdr z))) ((null? z) st))) ;;; Implements implicit begin and internal defines for lambda bodies. (define (preprocess-body body st) (let ((definition? (lambda (exp) (and (pair? exp) (eq? (car exp) 'define)))) (definition-lhs cadr) (definition-rhs caddr)) (let loop ((l (map (lambda (exp) (preprocess exp st)) body)) (d '())) (if (null? l) (error "no non-definitions in body" body) (let ((exp (->core (car l)))) ;Analyze (if (not (definition? exp)) (preprocess (if (null? d) `(begin ,@l) `(letrec ,(reverse d) ,@l)) scheme-syntax-table) (loop (cdr l) (cons `(,(definition-lhs exp) ,(make-preprocessed (definition-rhs exp))) d)))))))) ; Fin  Received: from geneva (TCP 2206400372) by MC.LCS.MIT.EDU 28 Mar 87 16:14:05 EST Received: by GENEVA.AI.MIT.EDU; Sat, 28 Mar 87 16:11:21 est Date: Sat, 28 Mar 87 16:11:21 est From: jinx@GENEVA.AI.MIT.EDU (Guillermo J. Rozas) Message-Id: <8703282111.AA05557@geneva> To: KMP@STONY-BROOK.SCRC.Symbolics.COM Cc: willc%tekchips.tek.com@csnet-relay, RRRS-Authors@MC.LCS.MIT.EDU In-Reply-To: Kent M Pitman's message of Sat, 28 Mar 87 14:35 EST <870328143552.3.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM> Subject: Let's get together again I agree with KMP. I think the weekend before, if at all possible, would be better. I also think that a new meeting would be a good idea.  Received: from YUKON.SCRC.Symbolics.COM (TCP 30002424403) by MC.LCS.MIT.EDU 28 Mar 87 14:51:46 EST Received: from RIO-DE-JANEIRO.SCRC.Symbolics.COM by YUKON.SCRC.Symbolics.COM via CHAOS with CHAOS-MAIL id 185960; Sat 28-Mar-87 14:36:06 EST Date: Sat, 28 Mar 87 14:35 EST From: Kent M Pitman Subject: Let's get together again To: willc%tekchips.tek.com@csnet-relay cc: RRRS-Authors@MC.LCS.MIT.EDU In-Reply-To: <8703272312.AA03301@tekchips.TEK.COM> Message-ID: <870328143552.3.KMP@RIO-DE-JANEIRO.SCRC.Symbolics.COM> I'm all for getting together, but because my (paid) job is Lisp and not Scheme, I'd be happier if it were over a weekend so I wouldn't have to take time away from work. Also, many of the X3J13 participants will be arriving for Monday subcommittee meetings and if they came Saturday, they could get cheaper fares. Note, too, that Thursday/Friday is 4th of July weekend and not everyone will necessarily want to spend that time in Boston -- though certainly I plan to be there so this last point is not a problem for me, just another possible reason why the weekend before (27-28 June) might be better for meeting.  Received: from AI.AI.MIT.EDU (CHAOS 3130) by MC.LCS.MIT.EDU 28 Mar 87 00:06:45 EST Date: Sat, 28 Mar 87 00:03:12 EST From: Jonathan A Rees Subject: multiple return values To: willc%tekchips.tek.com@RELAY.CS.NET cc: rrrs-authors@MC.LCS.MIT.EDU In-reply-to: Msg of 27 Mar 87 15:47:06 PST (Fri) from willc%tekchips.tek.com at RELAY.CS.NET Message-ID: <174983.870328.JAR@AI.AI.MIT.EDU> Date: 27 Mar 87 15:47:06 PST (Fri) From: willc%tekchips.tek.com at RELAY.CS.NET single: (E --> C) --> K 1. single = \ f e* . # e* = 1 --> f (e* ! 1), wrong "..." 2. single = \ f e* . # e* >= 1 --> f (e* ! 1), wrong "..." 3. single = \ f e* . # e* >= 1 --> f (e* ! 1), f unspecified I have already put in my vote for 1. I see no way to implement the proposed procedures in R3RS Scheme, but most implementations should find it easy to add them. If "wrong" doesn't imply "signals an error" then the following is a correct implementation of alternative 1. This is pretty much how the feature was implemented in T2. (define values-marker (list 'values-marker)) (define receive-values (lambda (thunk proc) (let ((vals (thunk))) (if (and (pair? vals) (eq? (car vals) values-marker)) (apply proc (cdr vals)) (proc vals))))) (define return-values (lambda vals (cons values-marker vals))) I think that the fact that this is so easy is a significant reason to favor alternative 1. ---- I find the feature to be pretty unuseable unless there is some syntactically sugared way to use RECEIVE-VALUES (viz. T's RECEIVE and CL's MULTIPLE-VALUE-BIND), but maybe this issue can be argued separately. Jonathan  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 27 Mar 87 21:58:11 EST Received: from relay2.cs.net by RELAY.CS.NET id ab29893; 27 Mar 87 21:49 EST Received: from tektronix.tek.com by RELAY.CS.NET id ag11897; 27 Mar 87 21:42 EST Received: by tektronix.TEK.COM (5.51/6.20) id AA12620; Fri, 27 Mar 87 15:14:08 PST Received: by tekchips.TEK.COM (5.31/6.19) id AA03301; Fri, 27 Mar 87 15:12:35 PST Message-Id: <8703272312.AA03301@tekchips.TEK.COM> To: rrrs-authors@MC.LCS.MIT.EDU Subject: Let's get together again Date: 27 Mar 87 15:12:31 PST (Fri) From: willc%tekchips.tek.com@RELAY.CS.NET It's been the better part of a year since many of us got to see each other at the 1986 Lisp conference, and two and a half years since we got together at Brandeis. The next X3J13 (Common Lisp) meeting will be in Boston or Cambridge 30 June and 1 July (a Tuesday and Wednesday), so David Bartley and I would like to suggest that we meet in Cambridge to discuss Scheme standardization issues on Thursday, 2 July, possibly spilling over into Friday morning, 3 July. We need volunteers to arrange for a room, prepare an agenda, and chair the meeting. Some issues that Bartley and I would like to see resolved are: multiple return values customizable reader number syntax and exactness macros optional arguments structures and opaque objects environments modules These are in rough order of our priorities, where we give priority to things that can be standardized easily as well as to things that are important. We'll be posting some proposals to this mailing list in hopes of generating some thought, interest, or at least discussion before we next get together. Another thing we should talk about is what we want to come after Scheme. Peace, Will Clinger Tektronix, Inc.  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 27 Mar 87 21:55:00 EST Received: from relay2.cs.net by RELAY.CS.NET id ac29893; 27 Mar 87 21:49 EST Received: from tektronix.tek.com by RELAY.CS.NET id ah11897; 27 Mar 87 21:42 EST Received: by tektronix.TEK.COM (5.51/6.20) id AA14104; Fri, 27 Mar 87 15:48:41 PST Received: by tekchips.TEK.COM (5.31/6.19) id AA03757; Fri, 27 Mar 87 15:47:10 PST Message-Id: <8703272347.AA03757@tekchips.TEK.COM> To: rrrs-authors@MC.LCS.MIT.EDU Subject: multiple return values Date: 27 Mar 87 15:47:06 PST (Fri) From: willc%tekchips.tek.com@RELAY.CS.NET Our previous round of discussions on multiple return values reached no consensus. I want to try again with the very simple, specific proposal that follows. The proposal consists of additions and changes to the formal semantics that appears in R3RS, an informal description, and a rationale. FORMAL SEMANTICS [Notation: The "\" character should be read as a Greek lambda, and the "!" character should be read as a down-arrow.] Add a procedure RECEIVE-VALUES whose semantics is given by receive_values: E* --> K --> C receive_values = twoarg (\ e1 e2 k . applicate e1 <> (\ e* . applicate e2 e* k)) Add a procedure RETURN-VALUES whose semantics is given by return_values: E* --> K --> C return_values = \ e* k . k e* Either leave the equation of the auxiliary function "single" as is (equation 1 below), or change it as indicated in equation 2 or as indicated in equation 3. single: (E --> C) --> K 1. single = \ f e* . # e* = 1 --> f (e* ! 1), wrong "..." 2. single = \ f e* . # e* >= 1 --> f (e* ! 1), wrong "..." 3. single = \ f e* . # e* >= 1 --> f (e* ! 1), f unspecified INFORMAL DESCRIPTION (RECEIVE-VALUES thunk proc) procedure The first argument is a procedure of no arguments, the second is any procedure. Calls the first argument, obtaining 0 or more return values, and then calls the second argument on the value(s) returned by the first argument. See RETURN-VALUES. (receive-values (lambda () (return-values 3 7)) (lambda (a b) (* a b))) --> 21 (RETURN-VALUES x ...) procedure Takes any number of arguments, and returns them as multiple return values. [See the rationale for a discussion of how many return values a continuation expects, and the error conditions that may result when the expectations are not met.] See RECEIVE-VALUES. (receive-values (lambda () (return-values 'a 'b 'c)) vector) --> #(a b c) (letrec ((f (lambda (x) (if (zero? x) (g x) (g x)))) (g (lambda (x) (return-values x (- x)))) (h (lambda (x) (receive-values (lambda () (f x)) list)))) (h 3)) --> (3 -3) (letrec ((f (lambda (x) (+ (g x) 13))) (g (lambda (x) (return-values x (- x)))) (h (lambda (x) (receive-values (lambda () (f x)) list)))) (h 3)) --> error [equation 1] --> (16) [equation 2 or 3] (receive-values (lambda () (return-values)) vector) --> #() (receive-values (lambda () (return-values 1)) (lambda (x . y) y)) --> () (receive-values (lambda () (return-values)) (lambda (x . y) y)) --> error (list (return-values 'a 'b 'c 'd)) --> (a) (car (list (return-values))) --> error [equation 1 or 2] --> unspecified [equation 3] RATIONALE This proposal is along the lines of multiple return values as in Common Lisp, but is somewhat simpler and more rational. The simplicity of the proposal, as compared to the exposition in CLtL, is attributable to a better choice of primitives and to Scheme's tail-recursive semantics. RECEIVE-VALUES and RETURN-VALUES correspond to T3's RECEIVE-VALUES and RETURN. The name "RETURN" was rejected because it would confuse people who are accustomed to the use of RETURN in Common Lisp and similar Lisps. Note that these are procedures, not syntax, and that neither would be essential Scheme. The arguments to RECEIVE-VALUES are reversed from the way they are in T3. Feel free to argue the argument order. Argue also about which equation we should choose for "single". It determines what happens in the case where RETURN-VALUES returns to a continuation that was not created by RECEIVE-VALUES. Equation 1 says that in such a case there must be exactly one return value. Equation 2 says that in such a case there must be at least one value; the extra values are ignored. Equation 3 allows zero return values, in which case the value received by the continuation is unspecified. No matter which equation is chosen, there is no difference between returning a single value in the usual way and returning a single "multiple value" using RETURN-VALUES. I didn't give equations for the extreme positions. The fascist position would say that it is always an error for RETURN-VALUES to return to a continuation that was not created by RECEIVE-VALUES. The commonlisp position would say that when zero values are returned to a continuation that is expecting one value, then the symbol NIL is passed to the continuation. If there is sufficient demand, I will post equations for these. If we interpret the use of "wrong" in the semantic equations to mean "is an error" instead of "signals an error", then all of the equations allow implementations in which Scheme multiple return values are compatible with the semantics of Common Lisp's multiple return values. This should make it easier to support a Scheme subset in Common Lisp or vice versa. I see no way to implement the proposed procedures in R3RS Scheme, but most implementations should find it easy to add them. William Clinger  Received: from kleph (TCP 2206400254) by MC.LCS.MIT.EDU 17 Mar 87 16:19:07 EST Received: by KLEPH.AI.MIT.EDU; Tue, 17 Mar 87 16:08:11 est Date: Tue, 17 Mar 87 16:08:11 est From: cph@KLEPH.AI.MIT.EDU (Chris Hanson) Message-Id: <8703172108.AA02948@kleph> To: jar@ai Cc: rrrs-authors@mc Subject: eqv? I believe that the paragraph starting "There is only one empty list..." on page 13, section 6.2 of R3RS should be modified. In MIT Scheme, the statement that (eqv? "" "") ==> #t is actually false, because there is a user operation, `set-string-length!', which distinguishes between two empty strings. I think that the same might be true of #() in an implementation with `vector-grow!'. The statement should be modified to indicate that it is true given the operations described in the report, and may not be true in a given implementation with extended operations.  Received: from RELAY.CS.NET (TCP 1201000005) by MC.LCS.MIT.EDU 12 Mar 87 09:03:01 EST Received: from relay2.cs.net by RELAY.CS.NET id aa09740; 12 Mar 87 8:57 EST Received: from indiana by RELAY.CS.NET id ac00825; 12 Mar 87 8:52 EST Date: Wed, 11 Mar 87 23:58:18 est From: "R. Kent Dybvig" To: JAR@MC.LCS.MIT.EDU Subject: Re: test suite candidate Cc: rrrs-authors@MC.LCS.MIT.EDU I believe I was the one who volunteered to work on this at last year's Lisp conference, and I plan to do so over the summer. I'll save your program away (it does work in Chez Scheme, incidentally). I also welcome any other test programs people have written or wish to write. We have a favorite continuation example here, but it is probably more challenging to people than to Scheme systems. It is "mondo-bizarro", whose definition is given below. Work it out on paper before trying it out. (define mondo-bizarro (lambda () (let ([k (call/cc (lambda (c) c))]) (write 1) (call/cc (lambda (c) (k c))) (write 2) (call/cc (lambda (c) (k c))) (write 3)))) Kent  Received: from zurich (TCP 2206400260) by MC.LCS.MIT.EDU 10 Mar 87 22:32:51 EST Received: by ZURICH.AI.MIT.EDU; Tue, 10 Mar 87 22:08:22 est Date: Tue, 10 Mar 87 22:08:22 est From: jar@ZURICH.AI.MIT.EDU (Jonathan Rees) Message-Id: <8703110308.AA07187@zurich> To: rrrs-authors@mc.lcs.mit.edu Subject: test suite candidate Reply-To: JAR@AI.AI.MIT.EDU Has anyone worked on a test suite? Here's a suggestion for inclusion, which, fortunately, works in the three implementation in which I tried it. I leave the significance of this test as an exercise. - Jonathan (define (tst) (define k1 #f) (define k2 #f) (define cwcc call-with-current-continuation) (define step 0) (define (detect-lossage) (set! step (+ step 1)) (case step ((1) (cwcc (lambda (k) (set! k1 k) 'a))) ((2) (cwcc (lambda (k) (set! k2 k) 'b))) ((4) 'd))) (let ((answer (list (detect-lossage) (detect-lossage)))) (set! step (+ step 1)) (case step ((3) (k1 'c)) ;answer = (a b) or (b a) ((5) (k2 'e)) ;answer = (c d) or (d c) ((6) (cond ((or (equal? answer '(a e)) (equal? answer '(e a))) 'wins) ((or (equal? answer '(c e)) (equal? answer '(e c))) 'loses) (else (list 'really-loses answer)))))))