Received: from yale by MIT-MC.ARPA 20 Nov 85 06:53:40 EST Received: by Yale-Bulldog.YALE.ARPA; 19 Nov 85 23:47:19 EST (Tue) Date: 19 Nov 85 23:47:19 EST (Tue) From: Message-Id: <8511200447.AA14657@Yale-Bulldog.YALE.ARPA> Subject: PP'ing interpreted OBJECTs... To: t-discussion@YALE.ARPA PP does something strange with OBJECTs, as illustrated by the following transcript. Am I doing the right thing? How do I get a non-compiled OBJECT to PP correctly? > (define foo (object (lambda () 'value-of-foo) ((identification self) 'foo) ((print self stream) (format stream "#{FOO}")))) [Defining FOO] #{FOO} > (pp foo) ** Error: operation not handled (COMPILED-CODE-SOURCE ()) >> *** EOF *** ;; Adding a PRETTY-PRINT method doesn't help. ;; ------------------------------------------ > (define foo (object (lambda () 'value-of-foo) ((identification self) 'foo) ((print self stream) (format stream "#{FOO}")) ((pretty-print self stream) (format stream "#{FOO}")))) [Redefining FOO] #{FOO} > (pp foo) ** Error: operation not handled (COMPILED-CODE-SOURCE ()) >> (procedure? foo) T It seems to me that T thinks FOO is a procedure and so tries to do a WHERE-DEFINED on it when I try to PP it. Shouldn't PP first look for a PRETTY-PRINT method, or at least be smart enough not to look for the WHERE-DEFINED of a interpreted object? Or did I do something wrong? -- Ashwin. -------  Received: from CSNET-RELAY.ARPA by MIT-MC.ARPA 20 Nov 85 11:04:42 EST Received: from brown by csnet-relay.csnet id ab12205; 20 Nov 85 10:54 EST Received: from with MMDF via PhoneNet by Brown.CSnet; 19 Nov 85 22:51-EDT Message-Id: <8511200350.AA06351@mailhost.CS.Brown.CSNet> Date: 19 Nov 85 (Tue) 22:50:43 EST From: Keiji Kanazawa To: t-discussion@mit-mc.arpa Subject: suspend T What modifications do I need to make to T2.27 to enable it to suspend on sr9 (DOMAIN/IX) Apollos? Do I bother?  Received: from yale by MIT-MC.ARPA 20 Nov 85 12:19:20 EST Received: by Yale-Bulldog.YALE.ARPA; 20 Nov 85 10:50:28 EST (Wed) Date: 20 Nov 85 10:50:28 EST (Wed) From: Message-Id: <8511201550.AA02556@Yale-Bulldog.YALE.ARPA> Subject: re: PP'ing interpreted OBJECTs... To: ram@YALE.ARPA Cc: t-discussion@YALE.ARPA That looks like a bug to me, but there is something you can do if you are willing to sacrifice some of the functionality of OBJECTs. The problem seems to be coming from the fact that T thinks objects that are callable (ie that have a procedure associated with them) are procedures, not objects. If you make your objects uncallable, they pretty-print, so: > (define foo1 (object () ((pretty-print self str) (format str "#{Foo1}")))) #{Object 159} > (pp foo1) #{Foo1} > ;; Notice that uncallable objects print as #{Object x} and that callable ones print ;; as #{Procedure y} > (define foo2 (object (lambda () 'value-of-foo) ((pretty-print self str) (format str "#{Foo2}")))) #{Procedure 158} > (pp baz1) ** Error: operation not handled (COMPILED-CODE-SOURCE ()) >> *** EOF *** Unfortunately, operations also have the same pretty-printing problem. *sigh* Larry -------  Received: from yale by MIT-MC.ARPA 20 Nov 85 13:03:45 EST Received: by Yale-Bulldog.YALE.ARPA; 20 Nov 85 12:39:08 EST (Wed) Date: 20 Nov 85 12:39:08 EST (Wed) From: Message-Id: <8511201739.AA00562@Yale-Bulldog.YALE.ARPA> Subject: Re: #T, self-evaluation, and NULL-LIST =? FALSE. To: jar@mit-mc Cc: t-discussion@YALE.ARPA In-Reply-To: Jonathan A Rees , Tue, 19 Nov 85 14:59:54 EST In T, #T and #F are external syntax for true and false *objects*, not *expressions*. #T and #F are not themselves supposed to be evaluable expressions. Evaluable expressions which give true and false values are T and NIL, or, if you prefer, (TRUE) and (FALSE). However, note the following behavior: > (eq? (true) '#T) () What then is the purpose of #T (or equivalently the *TRUE-OBJECT*)? I realize the difference between #T and (TRUE), but I guess I was trying to say that I didn't see the need for #T, given that we have (TRUE) (or T, if you prefer). It just seemed like unnecessary syntax (shudder!) to me. In the long run I think the right thing to do is to somehow make the way that boolean and other objects evaluate (macroexpand) be a property of the syntax table... Again, why do we need syntax for booleans when we have T, NIL, (TRUE) and (FALSE)? ... (it's bad enough that numbers self-evaluate; where does one draw the line?)... I disagree. The value of 34 is 34, not ERROR. ... (It would have helped if we had distinguished #F from () back in 1981 when we had a chance.) We all use the fact that the null list and the false object are the same while programming. This isn't due to any theoretical confusion (any more than making use of (CAR '()) => () is); it just happens to be convenient sugar for something that occurs very often. The sugar helps in avoiding code clutter which would otherwise result from type checking all over the place. In addition, I think this also helps in defining the semantics of some functions, such as ASS. Now we can simply say that ASS returns a pair (which may be NIL if the key isn't in the A-list) without worrying about whether "not being in the A-list" means returning a NULL pair or the boolean FALSE. Of course, the user can always hand the result of ASS to (COND ((NULL? result) -not-found-) (ELSE -use-pair-)), but then this gets us back to the code clutter point. -- Ashwin. -------  Received: from yale by MIT-MC.ARPA 20 Nov 85 15:43:18 EST Received: by Yale-Bulldog.YALE.ARPA; 20 Nov 85 15:32:14 EST (Wed) Date: 20 Nov 85 15:32:14 EST (Wed) From: Message-Id: <8511202032.AA02418@Yale-Bulldog.YALE.ARPA> Subject: Re: #T, self-evaluation, and NULL-LIST =? FALSE. To: In-Reply-To: , 20 Nov 85 12:39:08 EST (Wed) Cc: T-discussion@YALE.ARPA In T, #T and #F are external syntax for true and false *objects*, not *expressions*. #T and #F are not themselves supposed to be evaluable expressions. Evaluable expressions which give true and false values are T and NIL, or, if you prefer, (TRUE) and (FALSE). However, note the following behavior: > (eq? (true) '#T) () What then is the purpose of #T (or equivalently the *TRUE-OBJECT*)? I realize the difference between #T and (TRUE), but I guess I was trying to say that I didn't see the need for #T, given that we have (TRUE) (or T, if you prefer). It just seemed like unnecessary syntax (shudder!) to me. The point is #T cannot be shadowed. Since TRUE is just an identifier it is not guaranteed to evaluate to the same thing in all environments. The manaul says that (TRUE) returns some true object not the cononical true object. In the long run I think the right thing to do is to somehow make the way that boolean and other objects evaluate (macroexpand) be a property of the syntax table... Again, why do we need syntax for booleans when we have T, NIL, (TRUE) and (FALSE)? No. T, NIL, TRUE, and FALSE are identifiers bound in the standard environment, and thus they can be shadowed. #T and #F are read syntax and are guaranteed to read as the canonical true and false objects in any environment using the standard read table. ... (it's bad enough that numbers self-evaluate; where does one draw the line?)... I disagree. The value of 34 is 34, not ERROR. No again. Your confusing the identifier represented by the character sequence "34" and the number 34. Maybe Jonathan can expand on this. ... (It would have helped if we had distinguished #F from () back in 1981 when we had a chance.) We all use the fact that the null list and the false object are the same while programming. ... The sugar helps in avoiding code clutter which would otherwise result from type checking all over the place. You shouldn't be. The null list and the false object are not semantically the same and for example the compiler could detect certain errors that it now can't if this difference were supported in the language. I don't see how making #F different from () causes code clutter, could you explain? - Jim  Date: Wed, 20 Nov 85 16:01:48 EST From: Jonathan A Rees Subject: #T, self-evaluation, and NULL-LIST =? FALSE. To: Ram@YALE.ARPA cc: T-DISCUSSION@MIT-MC.ARPA In-reply-to: Msg of 20 Nov 85 12:39:08 EST (Wed) from Message-ID: <[MIT-MC.ARPA].725680.851120.JAR> Date: 20 Nov 85 12:39:08 EST (Wed) From: However, note the following behavior: > (eq? (true) '#T) () This is consistent with the message I sent out; the value of T is only guaranteed to be true. It's not guaranteed to be any particular true object, and programs shouldn't ever depend on any aspect of its value, other than its trueness. It just happens in version 2.8, the variable T evaluates to the symbol T. In 2.9 it evaluates to something else. What then is the purpose of #T? I realize the difference between #T and (TRUE), but I guess I was trying to say that I didn't see the need for #T, given that we have (TRUE) (or T, if you prefer). It just seemed like unnecessary syntax (shudder!) to me. The purpose of the syntax #T is to give a way to write a true boolean value as a component of a composite literal datum. It's basically documentary: it gives a way to say that some part of a datum should be true, but it prevents someone reading the code from imagining that there's something important about the value used other than its trueness. E.g.: one might write (define (dark? color) (cond ((assq color '((brown . #t) (black . #t) (white . #f) (yellow . #f))) => cdr) (else (error "unknown color")))) If "t" is used instead of "#t", the code works the same, but using "#t" makes it just a little clearer what's going on. ... (it's bad enough that numbers self-evaluate; where does one draw the line?)... I disagree. The value of 34 is 34, not ERROR. Disagreement is fine. I agree that it's convenient to be able to write '34 instead of 34. I just wanted to point out that something strange is going on when things "self-evaluate," since it's not the case e.g. that (CONS X Y) evaluates to the list (CONS X Y). Applying Occam's razor here would dictate that the extra feature of self-evaluation for certain expressions is unnecessary, so the extra complication should be eliminated. Since T has this feature, the design of T is not consistent with Occam's razor. ... (It would have helped if we had distinguished #F from () back in 1981 when we had a chance.) We all use the fact that the null list and the false object are the same while programming. This isn't due to any theoretical confusion (any more than making use of (CAR '()) => () is); it just happens to be convenient sugar for something that occurs very often. ... It would also be convenient to define (1 V) to mean the same thing as (VREF V 1); that would avoid code clutter. There are some languages in which nearly all programs are correct. This makes for very concise code, and simplifies implementations since no error system or debugging facilities are needed. Having the domains boolean and list intersect is as theoretically confused as (CAR '()) => (), namely very. You have to go to great lengths in the documentation, implementation, and formal semantics to cause these things to happen. It certainly is well-defined (and you could therefore say it's not confused), but it's not elegant. I suppose it's a matter of taste. When you design a language you decide what the domains of various primitives should be, and what coercions are allowable when. In Snobol4 you can write "2" + "2" and get 4; in Algol68 you can write "2" + "2" and get "22". These are two of my favorite languages, and both have many excellent features which avoid code clutter. But these days I prefer disjoint domains, even if increased code clutter results. In particular, I think boolean, list, symbol, and number should all be disjoint domains. Simplifications like this make programs easier to understand and debug, and streamlines both the description and the implementation of the language.  Date: Wed, 20 Nov 85 16:09:13 EST From: Jonathan A Rees Subject: suspend T To: kgk%brown.csnet@CSNET-RELAY.ARPA cc: T-DISCUSSION@MIT-MC.ARPA In-reply-to: Msg of 19 Nov 85 (Tue) 22:50:43 EST from Keiji Kanazawa Message-ID: <[MIT-MC.ARPA].725684.851120.JAR> Date: 19 Nov 85 (Tue) 22:50:43 EST From: Keiji Kanazawa What modifications do I need to make to T2.27 to enable it to suspend on sr9 (DOMAIN/IX) Apollos? Do I bother? Sorry, no way. I think some kind of suspend for Aegis T may be in the works for a future release.  Date: Wed, 20 Nov 85 16:16:14 EST From: Jonathan A Rees Subject: PP'ing interpreted OBJECTs... To: Ram@YALE.ARPA cc: T-DISCUSSION@MIT-MC.ARPA In-reply-to: Msg of 19 Nov 85 23:47:19 EST (Tue) from Message-ID: <[MIT-MC.ARPA].725702.851120.JAR> Date: 19 Nov 85 23:47:19 EST (Tue) From: PP does something strange with OBJECTs, as illustrated by the following transcript. Am I doing the right thing? How do I get a non-compiled OBJECT to PP correctly? ** Error: operation not handled (COMPILED-CODE-SOURCE ()) >> *** EOF *** This is definitely a T bug, and ought to be fixed. Public service announcement: Remember, T development is a labor of love - I may be wrong about this, but I was under the impression that no one was getting paid to do it. Bugs like this are pretty easy track down (in this case, some piece of code is failing to check that for false before calling COMPILED-CODE-SOURCE, or something like that - use GREP or BACKTRACE to find the places where it's called, etc.), and the T sources are readily available, at Yale at least. Any help from users on actual bug fixes is appreciated, and leaves time for Jim & David & Richard to do more interesting things (like making suspend work on Aegis). If I remember your particular situation, you probably want to be handling the DISCLOSE operation anyhow, not PRINT or PRETTY-PRINT.  Received: from yale by MIT-MC.ARPA 21 Nov 85 10:51:47 EST Received: by Yale-Bulldog.YALE.ARPA; 21 Nov 85 10:06:04 EST (Thu) Date: 21 Nov 85 10:06:04 EST (Thu) From: Message-Id: <8511211506.AA14333@Yale-Bulldog.YALE.ARPA> Subject: Re: #T, self-evaluation, and NULL-LIST =? FALSE. To: t-discussion@YALE.ARPA In-Reply-To: Jonathan A Rees , Wed, 20 Nov 85 16:01:48 EST ... But these days I prefer disjoint domains, even if increased code clutter results. In particular, I think boolean, list, symbol, and number should all be disjoint domains. Simplifications like this make programs easier to understand and debug, and streamlines both the description and the implementation of the language. Whereas intersecting domains can lead to programs that are easier to write (the only item not on your list). APL hackers often use the fact that true and false are 1 and 0, respectively. For example, the APL 1-line prime-finder can count divisors just by summing the result of testing for zero remainders (summing-- not counting!). Code like this is indeed tricky to explain and defend, but it is also very easy to write and reconstruct. In the hacking days of my youth, I made use of any overlap in functionality I could find. (I even found some nice uses for the fact that UCI Lisp atoms were really lists with a special header!) These days, when most of the code I write is for tutorial or systems-type purposes, I too prefer the purer approach to language design, as exemplified by T. I'd like to think that I've seen the light, but it may just be a change in what I have to do. -------  Received: from yale by MIT-MC.ARPA 22 Nov 85 15:43:18 EST Received: by Yale-Bulldog.YALE.ARPA; 22 Nov 85 15:11:13 EST (Fri) Message-Id: <8511222011.AA01704@Yale-Bulldog.YALE.ARPA> Received: from YALE-RING by YALE-RES via CHAOS; Mon, 18 Nov 85 14:28:43 EST Subject: Bug in CHAR-NAME: A clue! Date: Mon, 18 Nov 85 14:28:45 EST From: Ashwin Ram To: T-Discussion@YALE.ARPA In-Reply-To: , 16 Nov 85 21:58:27 EST (Sat) CHAR-NAME RASSQ's down an internal table to look up a character's name. It turns out that if I reDEFINE RASS in *T-IMPLEMENTATION-ENV* with the exact code (from TSYS/LIST2.T) that it originally was anyway, CHAR-NAME now works fine. Curiouser and curiouser... Ashwin. -------  Received: from yale by MIT-MC.ARPA 6 Dec 85 15:29:22 EST Received: by Yale-Bulldog.YALE.ARPA; 6 Dec 85 15:13:04 EST (Fri) Date: 6 Dec 85 15:13:04 EST (Fri) From: Message-Id: <8512062013.AA06630@Yale-Bulldog.YALE.ARPA> Subject: REQUIRE and friends To: T-Discussion@YALE.ARPA [I realize that REQUIRE isn't released.] While trying to load T3 into ALFL, I got the following error message: ** Error: illegal to create new bindings in this environment (ENV-LOOKUP ... %LOOP:EXPAND-MACRO #t #t) This is apparently because I used REQUIRE within a BIND form - thus not at top level. Why can't I use REQUIRE at any other than top level??? Perhaps REQUIRE should take an optional environment parameter??? Should I just use *REQUIRE instead? Sigh. --- Jonathan -------  Date: Fri, 6 Dec 85 17:19:11 EST From: Jonathan A Rees Subject: REQUIRE and friends To: young@YALE.ARPA cc: T-DISCUSSION@MIT-MC.ARPA In-reply-to: Msg of 6 Dec 85 15:13:04 EST (Fri) from Message-ID: <[MIT-MC.ARPA].744766.851206.JAR> Date: 6 Dec 85 15:13:04 EST (Fri) From: [I realize that REQUIRE isn't released.] While trying to load T3 into ALFL, ... Wow! I want that version of ALFL. I got the following error message: ** Error: illegal to create new bindings in this environment (ENV-LOOKUP ... %LOOP:EXPAND-MACRO #t #t) This is apparently because I used REQUIRE within a BIND form - thus not at top level. Why can't I use REQUIRE at any other than top level? One day I was making some changes to the implementation of environments and felt like removing various random features like this. I think I justified this by saying I didn't want people trying to imagine that T's DEFINE worked like MIT Scheme's DEFINE, and in fact I wanted to leave open the option of changing this at some point, so I added some error checks to *DEFINE as a first step towards liberation. I think there were other considerations, but I can't recall now. This particular error can't possibly happen unless somehow you have your hands on one of T's "immutable environments," which you can't get unless you're running in a debugger B breakpoint or you're using undocumented things like REQUIRE and THE-ENVIRONMENT. Perhaps REQUIRE should take an optional environment parameter? REQUIRE isn't released because I never convinced myself it was a reasonable thing to have. It was inspired by the USING/ENVIRON feature of Cambridge Algol68, which has the semantics (although not the implementation) of textual inclusion. REQUIRE also happened to have the additional feature of demand loading of a named modules (this is what Common Lisp's REQUIRE was, later). Actually these are two (or three) different features which should have been implemented orthogonally; *REQUIRE sort of does the load-on-demand part. But I never got around to working on it. Part of it was that I could never figure out a good operating-system- and site-independent way to name modules. You would like to write modules which use and demand-load each other, but not have to change your source code when going from one machine to another. You would like each program to potentially have its own space of module names, to avoid collisions. (Common Lisp really lost on this count; the space of module (and package) names is flat.) *REQUIRE and LOAD maintain an environment-specific list of loaded modules, but I don't think that's quite the right thing. So eventually only the lower-level LOAD got put into the manual, and rather than document REQUIRE or *REQUIRE, we just waited hoping that once locales really worked, a good proposal for a module system would fall into our laps. It never did. John Lamping worked on one during summer of '84, but than I stopped doing T development, and I don't think anyone else has picked up on it. Should I just use *REQUIRE instead? Do whatever you want. *REQUIRE probably won't go away until there's a better way to deal with demand loading. Why don't you design & propose a module system for T? At the very least we could argue about the problem better if there was something solid to critique. All the basic mechanism is there: environment creation and access, loading files into mutable environments, tables, and so on, so there's plenty of opportunity for experimentation. You clearly don't want LOOP to be loaded into the same environment that your program is running in; but then somehow the system has to decide what environment LOOP should be loaded into, how to let it provide things for export, how to get the things it exports, and so on. There's a modest amount of engineering required. T's mutable environments are very general, and it's just a matter of deciding on a discipline for their use. Some protocol must be adopted as standard if we're going to have an environment where users can share software with each other.  Received: from yale by MIT-MC.ARPA 12 Dec 85 20:59:34 EST Received: by Yale-Bulldog.YALE.ARPA; 12 Dec 85 20:03:13 EST (Thu) From: Return-Path: Received: by sdcsvax.ARPA (5.31/4.41) id AA10181; Tue, 10 Dec 85 23:20:16 PST hops=0 Received: by vis.uucp (2.0/3.14) id AA18268; Tue, 10 Dec 85 21:46:18 pst Message-Id: <8512110546.AA18268@vis.uucp> To: t-discussion@YALE.ARPA Subject: Any T for Sun workstations? Date: 10 Dec 85 21:46:04 PST (Tue) Does anyone know of an implementation of T for a Sun workstation? Is anyone working on such an implementation? Does anyone want to work on such a thing? I'm willing to help if an implementation is in progress. Thanks for any info you have, _Greg Davidson Virtual Infinity Systems, San Diego greg@vis.uucp ucbvax--| telesoft--| davidson@sdcsvax.uucp decvax--+--sdcsvax--+--vis davidson@ucsd.arpa ihnp4--| noscvax--|  Received: from yale by MIT-MC.ARPA 13 Dec 85 23:22:19 EST Received: by Yale-Bulldog.YALE.ARPA; 13 Dec 85 23:11:27 EST (Fri) Message-Id: <8512140411.AA04269@Yale-Bulldog.YALE.ARPA> Return-Path: Date: 13 Dec 1985 23:14:24-EST From: Olin.Shivers@H.CS.CMU.EDU To: t-discussion@YALE.ARPA Subject: T on a Sun I believe some of the guys at the Centre Mondial Informatique et Resource Humaine in Paris were somewhat interested. There's a lot of interest in Scheme in France, it seems. -Olin  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 23 Dec 85 17:06:43 EST Received: by yale-cheops.YALE.ARPA; Mon, 23 Dec 85 17:00:51 est To: t-discussion@YALE.ARPA From: Jim Meehan Date: Mon, 23 Dec 85 16:45:06 EST Message-Id: <6600@csi-ring> Subject: Interaction between syntax-tables and environments There's been a lot of Common Lisp mail recently about the optional "environment" argument to MACROEXPAND and related functions, although environments are not very well explained in the Common Lisp manual. Of course, I think T's notion of syntax tables is much cleaner, and I was about to suggest that if they're going to make some changes, they might do well to consider something like syntax tables. But one nagging problem we've faced in T is that there *is* an interaction between macro-expanders and the environment, and it can cause trouble. Short, grotesque example: (DEFINE-SYNTAX (KAR X) `(CAR ,X)) (LET ((CAR CDR)) (KAR '(1 2 3))) => (2 3) The person who defined KAR probably wanted the expanded code to use the standard CAR, but because macros manipulate S-expressions and not values, there's nothing to prevent the environment from thwarting his intentions. Of course, you could write (DEFINE-SYNTAX (KAR X) `((*VALUE *STANDARD-ENV* 'CAR) ,X)) but then you lose in efficiency, open-compilability, etc. One way around this is to extend the rules for evaluation to permit the CAR of a form to be a procedure (as opposed to a symbol that is bound to a procedure). (A similar thing is currently implemented for special forms.) If this were implemented, we could write (DEFINE-SYNTAX (KAR X) `(,CAR ,X)) or, being very careful, (DEFINE-SYNTAX (KAR X) `(,(*VALUE *STANDARD-ENV* 'CAR) ,X)) and avoid the problem. This introduces other problems (e.g., external representation, compiler), but it might be workable. Comments? Other suggestions?  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 23 Dec 85 18:06:45 EST Received: by yale-cheops.YALE.ARPA; Mon, 23 Dec 85 17:59:43 est To: Jonathan A Rees From: Jim Meehan Date: Sun, 8 Dec 85 00:59:16 EST Message-Id: <6575@csi-ring> Subject: Re: REQUIRE and friends Cc: t-discussion@YALE.ARPA In-Reply-To: Your message of Fri, 6 Dec 85 17:19:11 EST ... So eventually only the lower-level LOAD got put into the manual, and rather than document REQUIRE or *REQUIRE, we just waited hoping that once locales really worked, a good proposal for a module system would fall into our laps. It never did. John Lamping worked on one during summer of '84, but than I stopped doing T development, and I don't think anyone else has picked up on it. Bill Ferguson and I designed and implemented a "module system" last year, and while it certainly doesn't solve all the world's problems, we're happy with the way it turned out. It has proved quite useful in preventing interference among various cooperating "subsystems" (e.g., graphics, Common Lisp interface, cross-compiler) that need separate read-tables, syntax-tables, and environments. In the process, we got rid of STREAM-READ-TABLE and ENV-SYNTAX-TABLE, and we introduced "workspaces" (triples consisting of a read-table, a syntax-table, and an environment). Workspaces are the coin of the realm for EVAL, LOAD, REQUIRE, HERALD, COMFILE, and various other sorts of transducers. I'd be happy to send the documentation to anyone interested.  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 23 Dec 85 18:21:09 EST Received: from yale (yale.arpa.ARPA) by yale-cheops.YALE.ARPA; Mon, 23 Dec 85 18:06:53 est Received: by Yale-Bulldog.YALE.ARPA; 23 Dec 85 17:52:33 EST (Mon) Return-Path: Date: Mon, 23 Dec 85 18:02:42 EST From: Jonathan A Rees Subject: Interaction between syntax-tables and environments To: csi!meehan@UUCP Cc: t-discussion@YALE.ARPA In-Reply-To: Msg of Mon 23 Dec 85 16:45:06 EST from Jim Meehan Message-Id: <[MC.LCS.MIT.EDU].765068.851223.JAR> Date: Mon, 23 Dec 85 16:45:06 EST From: Jim Meehan (DEFINE-SYNTAX (KAR X) `(CAR ,X)) (LET ((CAR CDR)) (KAR '(1 2 3))) => (2 3) The person who defined KAR probably wanted the expanded code to use the standard CAR, but because macros manipulate S-expressions and not values, there's nothing to prevent the environment from thwarting his intentions. Of course, you could write (DEFINE-SYNTAX (KAR X) `((*VALUE *STANDARD-ENV* 'CAR) ,X)) but then you lose in efficiency, open-compilability, etc. You don't lose if the compiler is reasonable. I think this is almost the right thing. I think future versions of the compiler will be able to compile this correctly. Of course, it just begs the question, since the user could have done (LET ((*VALUE LIST)) (KAR 3)), or bound *STANDARD-ENV*. Ultimately I think a new special form will have to be added to the language (absolute reference CAN be made to special forms); that's why *VALUE has a * in its name, just in case we decided to add a VALUE special form. (MIT Scheme has such a special form; it's called ACCESS, but takes its arguments in the opposite order.) One way around this is to extend the rules for evaluation to permit the CAR of a form to be a procedure (as opposed to a symbol that is bound to a procedure). (A similar thing is currently implemented for special forms.) If this were implemented, we could write (DEFINE-SYNTAX (KAR X) `(,CAR ,X)) You don't need to extend the syntax of combinations, you just need to extend the syntax of QUOTE: (DEFINE-SYNTAX (KAR X) `(',CAR ,X)) or, being very careful, (DEFINE-SYNTAX (KAR X) `(,(*VALUE *STANDARD-ENV* 'CAR) ,X)) There's no reason to do this; the macro expander knows perfectly what its own environment is (weel... on second thought... but let's not get into that); there's no problem with ITS binding of CAR. and avoid the problem. This introduces other problems (e.g., external representation, compiler), but it might be workable. This could be made to work for system-supplied procedures, but making it work for general user procedures would be very difficult; in the general case the system would have to invoke FTP or the international telephone or mail systems. One idea I'm considering is something resembling Internet "domain naming," which is basically a programming convention which allows one to name any object on any machine. If I can work the kinks out and if someone bothers to implement it, it may become part of some future release of T, and ultimately T may even be able to invoke FTP automatically. Your points are correct; I hope that this further illustrates to people just how intractible macros are. Don't use them if you can avoid it! The above is a terrible example; you could have written (define-integrable (kar x) (car x)) or (define-integrable kar car) without sacrificing a nanosecond of efficiency (this is one of the great features of T compilers). There are occasional cases where macros are desirable (I generally only use them for top-level forms), but this is not one.  Date: Sun, 29 Dec 85 21:02:27 EST From: Jonathan A Rees Subject: [csi!meehan%UUCP: syntax] To: T-DISCUSSION@MC.LCS.MIT.EDU Message-ID: <[MC.LCS.MIT.EDU].768311.851229.JAR> Date: Mon, 23 Dec 85 22:52:38 EST From: Jim Meehan To: Jonathan A Rees cc: csi!ferguson at UUCP Re: syntax Message-Id: <6603@csi-ring> In-Reply-To: Your message of Mon, 23 Dec 85 18:02:42 EST [Jonathan: If you think this would be interesting or appropriate for the T-DISCUSSION bboard, feel free to forward it there.] ========================================================================= ... (DEFINE-SYNTAX (KAR X) `(CAR ,X)) (LET ((CAR CDR)) (KAR '(1 2 3))) => (2 3) ... The above is a terrible example; you could have written (define-integrable (kar x) (car x)) Right. The example I should have used was this: (LET ((CAR CDR) (L '(1 2 3))) (POP L)) ========================================================================= ... I hope that this further illustrates to people just how intractible macros are. Don't use them if you can avoid it! ... There are occasional cases where macros are desirable (I generally only use them for top-level forms)... I'm puzzled. At the moment, in T 2.8, there are 13 special forms and 71 macros in the *STANDARD-SYNTAX-TABLE*. I'd put the 71 macros into 3 categories: I. Macros useful primarily at top level: DEFINE-CONSTANT DEFINE-PREDICATE DEFINE-STRUCTURE-TYPE DEFINE-SYNTAX DEFINE-INTEGRABLE DEFINE-SETTABLE-OPERATION DEFINE (also inside LET) DEFINE-OPERATION DEFINE-METHODS II. Macros useful (i.e., reasonably meaningful) anywhere: DESTRUCTURE WITH-OUTPUT-TO-STRING DESTRUCTURE* PUSH CASE XCOND WITH-OUTPUT-WIDTH-STREAM XSELECT BLOCK0 WITH-INPUT-FROM-STRING MODIFY DECREMENT MACRO-EXPANDER OR LET* SELECT COND DELAY WITH-OPEN-STREAMS INCREMENT SET ITERATE WITH-OUTPUT-TO-LIST EXCHANGE MODIFY-LOCATION BIND* POP XCASE LET* DO AND SWAP UNWIND-PROTECT III. Macros that might be [reasonably implemented as] special forms, but are useful anywhere, not just at top level: OPERATION OBJECT LOCATIVE LOCALE LET LABELS CATCH BIND IV. Other macros (mostly implementation stuff): DEFINE-INSTANCE-METHODS %DEFINE-SYNTAX IGNORE DEFINE-MACRO DECLARE-SETTER REFERENCE ^ DEFINE-STRUCTURE-SELECTOR COMMENT IGNORABLE OPERATION-DISPATCH UNTRACE **BACKQUOTE-MARKER** GC-DEFER HANDLER IMPORT SYNONYM IF-INTEGRATED REQUIRE HERALD TRACE PP While there's lots of room to argue about whether certain macros (e.g., the ones in Categories I and III) could or should be special forms, I don't know how you can avoid all 32 of the macros in Category II, and I doubt you'd recommend making them all special forms.  Date: Sun, 29 Dec 85 21:34:52 EST From: Jonathan A Rees Subject: syntax To: csi!meehan%UUCP@YALE.ARPA cc: T-DISCUSSION@MC.LCS.MIT.EDU In-reply-to: Msg of Mon 23 Dec 85 22:52:38 EST from Jim Meehan Message-ID: <[MC.LCS.MIT.EDU].768328.851229.JAR> Date: Mon, 23 Dec 85 22:52:38 EST From: Jim Meehan While there's lots of room to argue about whether certain macros (e.g., the ones in Categories I and III) could or should be special forms, I don't know how you can avoid all 32 of the macros in Category II, and I doubt you'd recommend making them all special forms. This is a good point; however, there's a very big difference between language-provided syntactic extensions like AND, OR, and LET, and the fact that user-supplied macros are desirable. Clearly the language should have a tiny set of primitive special forms (5 is about the right number, although I think a T kernel would end up having about 11), and syntactic sugar should be clearly marked as such in any reasonable manual. I'll go over your catalog anyhow, to see whether the existence of any of T's macros would argue for the desirability of user-written macros. I don't think they do. II. Macros useful (i.e., reasonably meaningful) anywhere: COND XCOND CASE XCASE SELECT XSELECT OR DELAY SET ITERATE DO AND I use these, but practically never want to invent new things like them, so I wouldn't consider it a terrible inconvenience to have the set of such things (mostly pretty fundamental control constructs) bound at language design time. MACRO-EXPANDER This is a very peculiar one which I don't understand quite what to do with. It's probably completely unnecessary. DESTRUCTURE DESTRUCTURE* BLOCK0 DECREMENT LET* INCREMENT BIND* POP PUSH I rarely use any of the above, and given my druthers would probably prefer to see them disappear from the manual & implementation. WITH-OUTPUT-WIDTH-STREAM WITH-INPUT-FROM-STRING WITH-OPEN-STREAMS WITH-OUTPUT-TO-LIST UNWIND-PROTECT WITH-OUTPUT-TO-STRING These have no right to be macros. They should be procedures which take procedure arguments, just as in MIT Scheme. MODIFY MODIFY-LOCATION EXCHANGE SWAP Locations have second-class status in T, and if things like this are to exist at all, locations should be made first-class. III. Macros that might be [reasonably implemented as] special forms, but are useful anywhere, not just at top level: OPERATION OBJECT LOCATIVE LOCALE LET LABELS CATCH BIND I don't quite understand the distinction between II and III, but again I don't see quite how users would want to extend this set. CATCH and BIND should be procedurized; OBJECT should be primitive; all the others are trivial syntactic sugar, but deal with semantically primitive concepts, not special members of an open-ended class of features. IV. Other macros (mostly implementation stuff): DEFINE-INSTANCE-METHODS %DEFINE-SYNTAX IGNORE DEFINE-MACRO DECLARE-SETTER REFERENCE ^ DEFINE-STRUCTURE-SELECTOR COMMENT IGNORABLE OPERATION-DISPATCH UNTRACE **BACKQUOTE-MARKER** GC-DEFER HANDLER IMPORT SYNONYM IF-INTEGRATED REQUIRE HERALD TRACE PP Many of these (like IF-INTEGRATED) are disappearing, and exist only due to design or implementation inadequacies; others are part of the user interface, not the language (like PP and TRACE), and should not be implemented by expressions; others are either primitive or trivial. Again, I don't see how I, or users generally, would want to write macros similar or analogous to these. If they do it probably implies a gross deficiency in the language, and has a better solution than the sledgehammer of a user macro facility. I'm not saying there shouldn't be a macro facility, or that the language shouldn't have a limited amount of syntactic sugar, but rather that I practically never see a legitimate use of a macro by anyone other than a language designer. It's good to be able to be a language designer, but it's a subtle and difficult art, and correct, orthogonal implementation is even harder than correct, orthogonal design. If people have good counterexamples to this argument, I would like to see them. Jonathan  Received: from SU-SUSHI.ARPA by MC.LCS.MIT.EDU 29 Dec 85 23:55:33 EST Date: Sun 29 Dec 85 20:49:24-PST From: Andy Freeman Subject: Re: syntax To: JAR@MIT-MC.ARPA cc: csi!meehan%UUCP@YALE.ARPA, T-DISCUSSION@MIT-MC.ARPA In-Reply-To: <[MC.LCS.MIT.EDU].768328.851229.JAR> Message-ID: <12171136460.12.ANDY@SU-SUSHI.ARPA> Jonathan Rees (JAR@MIT-MC) writes: ... I practically never see a legitimate use of a macro by anyone other than a language designer. I haven't decided how to cover macros in my Common Lisp class, but I recently abused macros. I'd like to hear about other tools that would have worked as well. I've been studying coroutine and generator implementation techniques. As part of this, I implemented Icon's control structures several ways. My source programs are READable (as in, they can be read using READ), unlike real Icon programs, but I'm lazy. I didn't want to write code to read them. (I did write code to translate from my pseudo-Icon syntax to real Icon syntax so that my test programs could be run by my implementation as well as Arizona's real Icon implementation.) I defined two macros to support this project. The first one defines procedures; its first argument is the procedure name, the second is the argument list, and the subsequent arguments are the body of the definition. The macro translated this form into a block containing several side effects to store the various translations I made. (At one time, I generated five different versions.) Compiling a source file containing procedure definitions saved the work of creating these translations. (Initially, these translations were very expensive, often taking several cpu minutes for a small test program.) The second macro I used did whatever was necessary to execute one of the translation. Some of the translations are native T code, so in these cases, the macro expands to code that includes all of the previously defined procedures. In this case, compiling a file (containing the macro) compiles the T code that implements the program. This is very important; it would be necessary even if I did write code to read Icon programs and translate them. (Yes, I could write a T source file from the translations and then compile it, but ....) One of the versions I generated used upwards continuations. T doesn't support them, but chez scheme does. Therefore, I wanted my system to run in both chez scheme and T. The common subset of these two languages doesn't allow procedure or macro definition, so I used macros to define a larger common subset. (Other differences were filled in with procedures.) The decision to use macros instead of program to read and translate the pseudo-Icon programs helped here as well; I didn't have to write common subset I/O code. This isn't the first time I (or others) have pulled this common language trick. Once I convinced Interlisp and Maclisp to use the same source. Naturally this involved lots of hoops and whistles (mapcar in the common dialect was called @mapcar), but it was workable and used for a complete version of MRS. These may not count as "good counterexamples", but macros made my work possible. -andy -------  Date: Mon, 30 Dec 85 15:48:40 EST From: Jonathan A Rees Subject: syntax To: ANDY@SU-SUSHI.ARPA cc: T-DISCUSSION@MC.LCS.MIT.EDU, csi!meehan%UUCP@YALE.ARPA In-reply-to: Msg of Sun 29 Dec 85 20:49:24-PST from Andy Freeman Message-ID: <[MC.LCS.MIT.EDU].768944.851230.JAR> Your message doesn't contradict my quoted claim: ... I practically never see a legitimate use of a macro by anyone other than a language designer. You WERE being a language designer/implementor - you were designing an embedded implementation of Icon. I also use macros when I'm playing with new languages, or trying to run code in multiple Lisp implementations. The main reason I write macros instead of file transducers is so that the embedded language fits in neatly with all the user interface tools developed for use with the native Lisp: LOAD, the read-eval-print loop, editor interfaces, and compilers. I guess I don't see this technique as a case where one extends the syntax of the underlying language; really a new language is being invented. It would be nice to have multi-lingual user interfaces, so that one needn't write macros and pollute the underlying environment just in order to make it as easy to use the new language as it is to use the old. By not writing a file transducer, you weren't just being lazy; you were being modular. I'd like to have a better programming interface to the user interface than the macro chainsaw. - Jonathan.  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 30 Dec 85 18:22:28 EST Received: from yale (yale.arpa.ARPA) by yale-cheops.YALE.ARPA; Mon, 30 Dec 85 18:13:11 est From: Received: by Yale-Bulldog.YALE.ARPA; 30 Dec 85 15:43:08 EST (Mon) Date: 30 Dec 85 15:43:08 EST (Mon) Message-Id: <8512302043.AA07896@Yale-Bulldog.YALE.ARPA> Subject: Re: Interaction between syntax-tables and environments To: Jim Meehan Cc: t-discussion@YALE.ARPA In-Reply-To: Jim Meehan , Mon, 23 Dec 85 16:45:06 EST ... But one nagging problem we've faced in T is that there *is* an interaction between macro-expanders and the environment, and it can cause trouble. Of course there is. Macros, once expanded, call procedures and use other macros. Since these are gotten to through symbols, there must be an environment in which these symbols are evaluated. Now you gotta decide whether these work as in closures, or you want to look up the values at run-time. (The former, I hope, at least for procedures; possible also for macros (see below).) (DEFINE-SYNTAX (KAR X) `(CAR ,X)) (LET ((CAR CDR)) (KAR '(1 2 3))) => (2 3) The person who defined KAR probably wanted the expanded code to use the standard CAR... This is the most common case, since we love non-dynamic binding and use it (and expect it) all the time. Why should this work for procedures but not for macros? Comments? Other suggestions? I'm not sure how easy it is to separate syntax tables and environments (and, for that matter, read tables). I liked your "workspaces" idea. I think of syntaxes as being associated with the environments in which they are defined, in fact almost as if the "value" of a symbol was a syntax, analogous to the treatment of procedures, and syntax tables were an implementational detail. The advantage of this is uniformity with the closure idea. All but the most trivial macros refer to other macros (or special forms) and to other procedures too, just like procedures do. And just like procedures are closed at definition time and run in the environment in which they were defined, I would like my macros to have the symbols they use refer to the value they have in the definition environment. One way to ensure this is to use things like (*value *standard-env* 'CADR) ;(or a special form version of *VALUE) for standard procedures, just like you use (t-syntax 'BLOCK) = (syntax-table-entry *standard-syntax-table* 'BLOCK) for standard macros in T2.9 and T3. But it gets painful to wrap a reference around every symbol in a macro definition. Just like you can have: (define (kar x) (car x)) which you can import into another environment and have it work correctly even if CAR is defined differently there, I would like to be able to do the same with: (define-syntax (kar x) `(car ,x)) For the same reason, I think making the user wrap (T-SYNTAX ...) around syntax references is a copout; if KAR refers to a macro, it should be taken from the definition environment of KAR. Syntaxes seem ugly in T because they are too much like dynamic binding. Handling them like procedures should make them a nicer genre of beast to work with. -- Ashwin. -------  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 1 Jan 86 14:21:46 EST Received: from yale (yale.arpa.ARPA) by yale-cheops.YALE.ARPA; Wed, 1 Jan 86 13:30:26 est From: Received: by Yale-Bulldog.YALE.ARPA; 1 Jan 86 13:13:48 EST (Wed) Date: 1 Jan 86 13:13:48 EST (Wed) Message-Id: <8601011813.AA00491@Yale-Bulldog.YALE.ARPA> Subject: macros To: rees@YALE.ARPA Cc: t-discussion@YALE.ARPA, hudak@YALE.ARPA Jonathan: I'm not saying there shouldn't be a macro facility, or that the language shouldn't have a limited amount of syntactic sugar, but rather that I practically never see a legitimate use of a macro by anyone other than a language designer. Of course, this begs an answer to the question: "What is a language designer?" It would be tempting for each of us to argue that the only time we use macros is when we're playing the role of language designer; it's a rather subjective concept. In fact, for a language designer, macros are a rather constrained form of syntactic extension -- one might ultimately prefer tools that allow full context-free parsing. Since such tools don't currently exist in the convenient framework of a REPL and it's associated utilities (which is what's so nice about macros), then one has to resort to source-to-source transformations (compilation!) if macros don't fill the bill. If people have good counterexamples to this argument, I would like to see them. I almost never use macros, because it's almost always the case that procedural abstraction will do the job just as well (usually better). But it seems to me that legitimate uses of macros are always tied to the desire to delay the evaluation of something. For example, one of three macros that we use in the ALFL compiler is the following very *simple* one: (define-syntax (smt ob) `(let ((done ())) (lambda () (if done done (set done ,ob)) ) ) ) SMT stands for "self-modifying-thunk" and is our way of emulating graph-reduction without the inefficiency of T's DELAY (this works because () is not a valid value in ALFL). Do you think this use is legitimate? If so, am I being a language designer? I suppose I could have used a procedure like: (define (smt delayed-ob) (let ((done ())) (lambda () (if done done (set done (delayed-ob))) ) ) ) but then I would incur the inefficiency of *two* nullary closures instead of one. -Paul  Date: Thu, 2 Jan 86 16:19:33 EST From: Jonathan A Rees Subject: macros To: hudak@YALE.ARPA cc: T-DISCUSSION@MC.LCS.MIT.EDU In-reply-to: Msg of 1 Jan 86 13:13:48 EST (Wed) from Message-ID: <[MC.LCS.MIT.EDU].771100.860102.JAR> Obviously T's DELAY and FORCE should be made more efficient.  Received: from yale by MC.LCS.MIT.EDU 28 Jan 86 13:47:54 EST Received: by Yale-Bulldog.YALE.ARPA; 28 Jan 86 06:22:59 EST (Tue) Date: 28 Jan 86 06:22:59 EST (Tue) From: Message-Id: <8601281122.AA16563@Yale-Bulldog.YALE.ARPA> Subject: Of growing code and diminishing hacks... To: t-discussion@YALE.ARPA, scheme@mit-mc.arpa A SHORT BALLAD DEDICATED TO THE GROWTH OF PROGRAMS ================================================== by Ashwin Ram This is a tale of a sorry quest To master pure code at the T guru's behest I enrolled in a class that appealing did seem For it promised to teach fine things like T3 and Scheme The first day went fine; we learned of cells And symbols and lists and functions as well Lisp I had mastered and excited was I For to master T3 my hackstincts did cry I sailed through the first week with no problems at all And I even said "closure" instead of "function call" Then said the master that ready were we To start real hacking instead of simple theory Will you, said he, write me a function please That in lists would associate values with keys I went home and turned on my trusty Apollo And wrote a function whose definition follows: (cdr (assq key a-list)) A one-liner I thought, fool that I was Just two simple calls without a COND clause But when I tried this function to run CDR didn't think that NIL was much fun So I tried again like the good King of yore And of code I easily generated some more: (cond ((assq key a-list) => cdr)) It got longer but purer, and it wasn't too bad But then COND ran out and that was quite sad Well, that isn't hard to fix, I was told Just write some more code, my son, be bold Being young, not even a moment did I pause I stifled my instincts and added a clause (cond ((assq key a-list) => cdr) (else nil)) Sometimes this worked and sometimes it broke I debugged and prayed and even had a stroke Many a guru tried valiantly to help But undefined datums their efforts did squelch. I returneth once more to the great sage of T For no way out of the dilemma I could see He said it was easy -- more lines must I fill with code, for FALSE was no longer NIL. (let ((val (assq key a-list))) (cond (val (cdr val)) (else nil))) You'd think by now I might be nearing the end Of my ballad which seems bad things to portend You'd think that we could all go home scot-free But COND eschewed VAL; it wanted #T So I went back to the master and appealed once again I said, pardon me, but now I'm really insane He said, no you're not really going out of your head Instead of just VAL, you must use NOT NULL instead (let ((val (assq key a-list))) (cond ((not (null? val)) (cdr val)) (else nil))) My song is over and I'm going home to bed With this ineffable feeling that I've been misled And just in case my point you have missed Somehow I preferred (CDR (ASSQ KEY A-LIST)) :-) ================================================== -------  Received: from yale by MC.LCS.MIT.EDU 29 Jan 86 11:58:54 EST Received: by Yale-Bulldog.YALE.ARPA; 29 Jan 86 02:10:33 EST (Wed) From: Return-Path: Received: from Cabernet.ms by ArpaGateway.ms ; 28 JAN 86 23:49:12 PST Date: 28 Jan 86 23:36 PST Subject: Re: Of growing code and diminishing hacks... In-Reply-To: 's message of 28 Jan 86 06:22:59 EST (Tue) To: ram@YALE-RING.YALE.ARPA Cc: t-discussion@YALE.ARPA, scheme@MC.LCS.MIT.EDU Message-Id: <860128-234912-1014@Xerox> (define (overloaded-cdr val) (if (null? val) nil (cdr val))) (overloaded-cdr (assq key a-list)) In other words, if you want a cdr that horribly overloads nil, then write one. As for me, I think of a cons cell as an object with car and cdr fields in it, just as a point is an object with x and y fields in it. How about: (define (overloaded-x point) (if (null? point) nil (x point)))  Received: from yale by MC.LCS.MIT.EDU 29 Jan 86 12:15:24 EST Received: by Yale-Bulldog.YALE.ARPA; 29 Jan 86 03:23:44 EST (Wed) From: Return-Path: Received: from Salvador.ms by ArpaGateway.ms ; 29 JAN 86 01:20:42 PST Date: 29 Jan 86 01:14 PST Subject: Re: Of growing code and diminishing hacks... In-Reply-To: 's message of 28 Jan 86 06:22:59 EST (Tue) To: ram@YALE-RING.YALE.ARPA Cc: t-discussion@YALE.ARPA, scheme@MC.LCS.MIT.EDU Message-Id: <860129-012042-1051@Xerox> And another thing. The only reason NIL == #F usually works out so well in lisps is that the most common domain of concern is lists. In both C and APL, FALSE == 0 since a very common domain of concern is numbers. Hopefully we are moving towards a programming style that is more abstract datatype or object based, and so the primacy of lists will diminish. In any case, I don't want my programming language prejudging for me what types of object should be my major concern, and compromising its foundations to optimize for that one type.  Received: from yale by MC.LCS.MIT.EDU 29 Jan 86 12:52:02 EST Received: by Yale-Bulldog.YALE.ARPA; 29 Jan 86 08:12:57 EST (Wed) Return-Path: Date: Wed, 29 Jan 86 08:58:51 EST From: "George J. Carrette" Subject: Overloading of empty list as false. To: Miller.pa@XEROX.COM Cc: SCHEME@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA, ram@YALE-RING.ARPA In-Reply-To: Msg of 29 Jan 86 01:14 PST from Miller.pa at Xerox.COM Message-Id: <[MC.LCS.MIT.EDU].800287.860129.GJC> The primacy of lists in lisp is due to the fact that lisp is its own meta language and the vocabulary of that meta language is constructed inductively from lists, symbols and other constants. Furthermore, the most general graphs can be constuctured entirely in terms of bifurcations represented as cons cells; and bifurcations have a primacy over trifurcations etc. Topping this off by using the logical falsity constant as the token to mark the end of certain kinds of graphs is entirely natural definition to use. The lists themeselves will remain in their primacy as a prefered construct of efficient assembly language programming, (especially if this means your assembly language is LISP on a LISPMACHINE). Take note Plummer's multilisp emulator that he implemented on the 3600: Comments in the code indicating that using (SETQ *STACK* (CONS ELEMENT *STACK*)) was more efficient than using the C/FORTRAN/PASCAL style INDEX plus ARRAY, because the GC overhead was smaller than the expense of the extra instructions and memory references needed to manipulate the more complicated data structure. But I am arguing the barn door closed after the cows have left. The recent slant of revised-revised-report-on-scheme has indeed cleaned up things to make them more acceptable to the general community; throwing out all the obvious meta language machinery and with it much of the preference for lists. The reason that FALSE == 0 in C is not due to the concern for the domain of numbers. (Since in C one will often mark the end of character strings with 0, and represent the NULL pointer as 0 also). FALSE == 0 because of the instruction sets and memory organizations of the machines on which C was developed. Similarly in PDP10 Maclisp and CADR Lispmachine NIL == 0 (as a machine location address).  Received: from yale by MC.LCS.MIT.EDU 29 Jan 86 13:06:15 EST Received: by Yale-Bulldog.YALE.ARPA; 29 Jan 86 09:39:05 EST (Wed) Date: 29 Jan 86 09:39:05 EST (Wed) From: Message-Id: <8601291439.AA10931@Yale-Bulldog.YALE.ARPA> Subject: Re: Of growing code and diminishing hacks... To: Cc: t-discussion@YALE.ARPA, scheme@mit-mc.arpa In-Reply-To: , 28 Jan 86 23:36 PST (define (overloaded-cdr val) (if (null? val) nil (cdr val))) (overloaded-cdr (assq key a-list)) In other words, if you want a cdr that horribly overloads nil, then write one. As for me, I think of a cons cell as an object with car and cdr fields in it, just as a point is an object with x and y fields in it. How about: (define (overloaded-x point) (if (null? point) nil (x point))) So now we have a proliferation of functions. You could just as well think of CAR and CDR as operations, and NIL as an object that handles them by returning NIL. Much cleaner. Well, maybe not; I guess that's debatable. I think the code is cleaner even though the semantics that the compiler must implement may become a little hairier. But that's what compilers are for :-). -------  Received: from yale by MC.LCS.MIT.EDU 29 Jan 86 13:20:14 EST Received: by Yale-Bulldog.YALE.ARPA; 29 Jan 86 09:49:57 EST (Wed) Date: 29 Jan 86 09:49:57 EST (Wed) From: Message-Id: <8601291449.AA11227@Yale-Bulldog.YALE.ARPA> Subject: Re: Of growing code and diminishing hacks... To: Cc: t-discussion@YALE.ARPA, scheme@mit-mc.arpa In-Reply-To: , 29 Jan 86 01:14 PST And another thing. The only reason NIL == #F usually works out so well in lisps is that the most common domain of concern is lists. In both C and APL, FALSE == 0 since a very common domain of concern is numbers. I didn't say that NIL was in any way the best choice for FALSE across all languages. In Lisps, NIL = #F is just as reasonable as 0 = FALSE in C or APL. Try telling a C programmer that 0 won't be FALSE anymore. -------  Received: from yale by MC.LCS.MIT.EDU 18 Feb 86 17:31:04 EST Received: by Yale-Bulldog.YALE.ARPA; 18 Feb 86 15:48:52 EST (Tue) Return-Path: Received: by ll-vlsi.ARPA (4.12/4.7) id AA10471; Tue, 18 Feb 86 15:52:19 est Date: Tue, 18 Feb 86 15:52:19 est From: young@ll-vlsi.ARPA (George Young) Message-Id: <8602182052.AA10471@ll-vlsi.ARPA> To: t-discussion-request@YALE.ARPA, t-discussion@YALE.ARPA I am a new user of t2.9, (hoping for t3) running bsd4.2 on a vax/780, developing cad software for wafer-scale integration. Please add me to the t-discussion mailing list (or whatever appropriate mailing list exists). Thanks, George R. Young ( young@ll-vlsi.arpa ) MIT Lincoln Laboratory, Lexington, Mass. 01273  Received: from yale by MC.LCS.MIT.EDU 21 Feb 86 21:43:16 EST Received: by Yale-Bulldog.YALE.ARPA; 21 Feb 86 17:31:16 EST (Fri) Date: 21 Feb 86 17:31:16 EST (Fri) From: Ashwin Ram Message-Id: <8602212231.AA15193@Yale-Bulldog.YALE.ARPA> Subject: CASE and SELECT To: t-bugs@YALE.ARPA Cc: t-users@YALE.ARPA, t-discussion@YALE.ARPA BUG: ---- I think there is an inconsistency in the definition of CASE and SELECT in T. Both should take an extra first argument, which is the predicate to use in the comparison, and CASEQ and SELECTQ should be defined to use EQ? as the default predicate. (This is in keeping with MEM? and MEMQ?, ASS and ASSQ, etc.) Similarly, there may also be a CASEV and SELECTV. FIX: ---- The fixed code for CASE follows. Feel free to use it if you like. (I've been calling it CASEF so as not to clobber the original CASE, but I think that CASE and CASEQ is a better way to go.) The code is tested. ;;****************************************************************************** ;; CASE with specifiable PREDicate to compare the cases with. ;; Original CASE is equivalent to: (CASE eq? key . clauses) [now called CASEQ]. ;; Ashwin Ram, May 1985. (define **case-fell-off-end** '**case-fell-off-end**) (define-syntax (case pred key . clauses) (labels (((expand-case-1 keyvar clauses) (if (atom? clauses) '**case-fell-off-end** (let ((clause (car clauses)) (lose (lambda () (syntax-error "bad ~s clause syntax: ~s" 'case (car clauses))))) (cond ((atom? clause) (lose)) ((list? (car clause)) `(if (or ,@(map (lambda (k) `(,pred ,keyvar ',k)) (car clause))) ,(blockify (cdr clause)) ,(expand-case-1 keyvar (cdr clauses)))) ((memq? (car clause) '(t else)) (blockify (cdr clause))) (t (lose))))))) (let ((keyvar '%%%%key%%%%)) `((lambda (,keyvar) ,(expand-case-1 keyvar clauses)) ,key)))) (define-syntax (xcase pred key . clauses) `(case ,pred ,key ,@clauses (else (losing-xcase)))) (define (losing-xcase) (error "no clause selected in ~s expression" 'xcase)) (define-syntax (caseq key . clauses) `(case eq? ,key ,@clauses)) (define-syntax (casev key . clauses) `(case alikev? ,key ,@clauses)) ;;****************************************************************************** -------  Received: from yale-bulldog by MC.LCS.MIT.EDU 26 Feb 86 14:11:06 EST Received: by Yale-Bulldog.YALE.ARPA; 26 Feb 86 13:45:38 EST (Wed) Date: 26 Feb 86 13:45:38 EST (Wed) From: Charles Martin Message-Id: <8602261845.AA07245@Yale-Bulldog.YALE.ARPA> Subject: Re: Bug fix for Ashwin's CASE To: Olin.Shivers@H.CS.CMU.EDU Cc: ram@YALE.ARPA, t-discussion@YALE.ARPA In-Reply-To: Olin.Shivers@H.CS.CMU.EDU, 26 Feb 1986 07:09:50-EST Minor programming style point. Instead of doing things like (define-syntax (case pred key . clauses) (let ((comparator '%%%%casefun%%%%)) ... )) I've always preferred constructions such as (define-syntax (case pred key . clauses) (let ((comparator (generate-symbol 'CASE-FUN))) ... )) (Personally, "%%%%CASEFUN%%%%" is one of my favorite temporary variable names, so my code would break with your version... :-) -------  Received: from yale-bulldog by MC.LCS.MIT.EDU 25 Mar 86 14:38:56 EST Received: by Yale-Bulldog.YALE.ARPA; 25 Mar 86 14:31:11 EST (Tue) Date: 25 Mar 86 14:31:11 EST (Tue) From: Jonathan Young Message-Id: <8603251931.AA09255@Yale-Bulldog.YALE.ARPA> Subject: Tables To: T-Discussion@YALE.ARPA I would like to see some discussion about desirable features for the T table package. Recall that the current ("Released", although it isn't in the manual) table package supports the following operations: (MAKE-TABLE tag) => table (TABLE-ENTRY table key) => value or nil if none (settable) (SET-TABLE-ENTRY table key value) => undefined (adds an association) Now, the wish list. Clearly, it is desirable to have hash tables where the hash function and comparision function are other than POINTER-HASH (or some other hack) and EQ?. Obvious examples are , , and . Weak Tables. A table is a list of associations - pairs of keys and values. If the key is garbage, i.e., is no longer accessible, I would like the association (i.e. the pointer to the value) to go away. This is not implementable in the current scheme. Table Walking. It is desirable (occasionally) to apply a procedure to each pair in a table. This is possible in the current scheme only if you put a layer on top of the table package. Generators. I often write the following idiom: (or (table-entry table key) (set (table-entry table key) (make-value key))) This would be eliminated by the provision of a generator procedure to be called in the case when there is no value associated with the key in a call to TABLE-ENTRY. Before someone goes out and blindly writes a new table package, I'd like to hear more feedback. Are these idioms you use a lot? Are there other ideas you really need? Is this even the proper abstraction? --- Jonathan -------  Received: from yale-bulldog by MC.LCS.MIT.EDU 26 Mar 86 10:20:38 EST Received: by Yale-Bulldog.YALE.ARPA; 26 Mar 86 07:13:32 EST (Wed) Date: 26 Mar 86 07:13:32 EST (Wed) From: Larry Hunter Message-Id: <8603261213.AA18953@Yale-Bulldog.YALE.ARPA> Subject: tables To: young@YALE-BULLDOG.YALE.ARPA Cc: t-discussion@YALE.ARPA I agree that it would be nice to be able to specify the hash and comparison functions. The nonstandard stuff I use is a table-walker, an association-list to table conversion (and vice versa) and, for my own perverse reasons, I sometimes need to get back a random (not arbitrary) element from a table. One thing that bothers me is that table-entries that have never been defined return nil. I often want to discriminate between values that have never been set and ones that have been set to nil. Shouldn't uninitialized table-entries return some undefined value instead of nil? Larry -------  Received: from yale-bulldog by MC.LCS.MIT.EDU 26 Mar 86 11:04:36 EST Received: by Yale-Bulldog.YALE.ARPA; 26 Mar 86 10:54:44 EST (Wed) Date: 26 Mar 86 10:54:44 EST (Wed) From: Jonathan Young Message-Id: <8603261554.AA21038@Yale-Bulldog.YALE.ARPA> To: Hunter@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: Tables returning nil if no value One thing that bothers me is that table-entries that have never been defined return nil. I often want to discriminate between values that have never been set and ones that have been set to nil. Shouldn't uninitialized table-entries return some undefined value instead of nil? The problem is that *any* value could be stored in the table, including "some undefined value". The correct solution is to return multiple values such as the following: (table-entry table key) => found?, value where found? is true if there was a pair in the table and value is undefined if found? is false. Any votes for this system? Against? --- Jonathan  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 26 Mar 86 14:47:45 EST Received: from LOCUS.UCLA.EDU (locus.ucla.edu.ARPA) by yale-cheops.YALE.ARPA; Wed, 26 Mar 86 14:37:49 est Date: Wed, 26 Mar 86 11:28:56 PST From: Scott Turner To: Jonathan Young Cc: t-discussion@yale.arpa Subject: Re: Tables returning nil if no value In-Reply-To: Message of 26 Mar 86 10:54:44 EST (Wed) from "Jonathan Young " <8603261554.AA21038@Yale-Bulldog.YALE.ARPA> Message-Id: <860326.192856z.02571.srt@ZEUS.LOCUS.UCLA.EDU> > One thing that bothers me is that table-entries that have never been > defined return nil. I often want to discriminate between values that > have never been set and ones that have been set to nil. Shouldn't > uninitialized table-entries return some undefined value instead of nil? > The problem is that *any* value could be stored in the table, including > "some undefined value". > The correct solution is to return multiple values such as the following: > (table-entry table key) => found?, value I hesitate to offer an alternative to "the correct solution", but in our hash table (HT) package here at UCLA, we have nil as the undefined value and an additional function, HT:KEY? that returns true if the key is defined in the table (even with a nil value) and false otherwise. This has the advantage that you can ignore the defined/undefined issue if you'd like. In general, our solution has been to have the application (built on top of HT) decide about the defined/undefined question. As far as what functions I'd like in a table package, here are the ones that we have in HT: ; Functions intended for use by mortal beings ; ; HT:CREATE HT? HT:REMOVE HT:PAIRS ; HT:ENTRY HT:PAIR FREE HT:KEY? ; HT:WALK DUMP HT:KEYS COPY ; HT:MAP HT:ADD HT:RECORDS HT:COMBINE ; HT:FIND-ENTRY HT:UPDATE HT:COUNT The unobvious ones: HT:FIND-ENTRY -- returns the first pair that satisfies a predicate. HT:ADD/UPDATE -- add assumes the key is new, update the key is old. DUMP, FREE and COPY are generic operations defined on many of the packages we have here. DUMP is a debug print-out, FREE releases an object to storage management, and COPY returns a copy of the object. COPY in particular is ill-defined and is slowly going away. Ashwin has a copy of this code if you'd care to look at it. It is largely based on the original HT code. The default hashing function is OBJECT-HASH, but the user can define another (as well as the equality predicate) in the call to HT:CREATE. -- Scott Turner  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 26 Mar 86 15:02:25 EST Received: from MC.LCS.MIT.EDU (mc.lcs.mit.edu.ARPA) by yale-cheops.YALE.ARPA; Wed, 26 Mar 86 14:58:03 est Date: Wed, 26 Mar 86 14:09:43 EST From: Jonathan A Rees Subject: Tables returning nil if no value To: young-jonathan@YALE.ARPA Cc: Hunter@YALE.ARPA, T-Discussion@YALE.ARPA In-Reply-To: Msg of 26 Mar 86 10:54:44 EST (Wed) from Jonathan Young Message-Id: <[MC.LCS.MIT.EDU].862572.860326.JAR> Here's what I had in mind when I added tables: I really wanted them to be extremely minimal, with very little structure. I wanted them to be as simple and primitive as pairs. They were to be viewed as primitive components out of which one could build higher-level abstractions. My inspiration was SNOBOL4's tables. I didn't like the idea of having a zillion bells and whistles like in Common Lisp, or worse, Zetalisp. It was always my intent that the tables created by MAKE-TABLE would be weak tables, and they clearly could be; that's why there's no TABLE-WALK. I never got around to implementing them that way, however. I'm not saying this is the best way for this feature to be, I'm just saying it's what I had in mind. The correct way to deal with lookup failure is NOT to return a second found? value, but instead to either build failure into the language (as in Prolog, Snobol, or Icon, or zetalisp's condition system), or to pass multiple continuations (like PDP-10 assembly language programmers do): (table-entry table key (lambda (val) ... success ...) (lambda () ... failure ...)) Given that neither of these alternatives seems particularly realistic (the first because it's too drastic and the second because it's just as cumbersome as dealing with multiple values), I think the way it is is better.  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 26 Mar 86 15:47:52 EST Received: from decwrl.DEC.COM (decwrl.dec.com.ARPA) by yale-cheops.YALE.ARPA; Wed, 26 Mar 86 15:26:25 est Received: from clark.ARPA (clark) by decwrl.DEC.COM (4.22.03/4.7.34) id AA05012; Wed, 26 Mar 86 12:24:56 pst Received: by clark.ARPA (4.12/4.7.34) id AA19878; Wed, 26 Mar 86 12:24:04 pst From: ellis@decwrl.DEC.COM (John R. Ellis) Message-Id: <8603262024.AA19878@clark.ARPA> Date: 26 Mar 1986 1222-PST (Wednesday) To: Jonathan Young Cc: T-Discussion@YALE.ARPA, Hunter@YALE.ARPA Subject: Re: Tables returning nil if no value In-Reply-To: Your message of 26 Mar 86 10:54:44 EST (Wed). <8603261554.AA21038@Yale-Bulldog.YALE.ARPA> The problem is that *any* value could be stored in the table, including "some undefined value". The typical solution is to have a unique value defined in the table interface, say *table-undefined*, which is used only for undefined table entries. There is no practical reason to store *table-undefined* in a table as an explicit value. The minor advantage of *table-undefined* compared with returning two values is that it makes many applications simpler and slighlty more efficient. These applications will look up a key's value and compare it for equality with some value they're holding; this test is a little easier if *table-undefined* is used as sentinel value, since there will be only one test instead of two.  Received: from yale-bulldog by MC.LCS.MIT.EDU 30 Mar 86 00:32:41 EST Received: by Yale-Bulldog.YALE.ARPA; 27 Mar 86 11:38:39 EST (Thu) Date: 27 Mar 86 11:38:39 EST (Thu) From: Ashwin Ram Message-Id: <8603271638.AA03707@Yale-Bulldog.YALE.ARPA> Subject: Re: Tables returning nil if no value To: Jonathan Young Cc: t-discussion@YALE.ARPA In-Reply-To: Jonathan Young , 26 Mar 86 10:54:44 EST (Wed) The correct solution is to return multiple values such as the following: (table-entry table key) => found?, value where found? is true if there was a pair in the table and value is undefined if found? is false. I don't think this solution is "correct", since it violates the semantics we intuitively expect. Given a table T, a key K and a value V, we would, in your scheme, have: (set (table-entry T K) V) (table-entry T K) ==> something not EQ? to V I would vote for a predicate TABLE-ENTRY? (like Scott's HT:KEY?) which checks whether K has an association in T. I liked your idea of generator functions. The user may then choose to return NIL if s/he then wishes. However, this is obviously orthogonal to the "found?" problem. Well, maybe it's not so obvious. If a table is used as a data structure common to two modules in a program, there is no a priori way for the one to know that an "undefined value" (as Ellis suggested) is in fact not a legitimate value stored in the table by the other. The only way it could do this is to test if the "undefined value" belonged to the co-domain of the function being implemented, which requires an extra test anyway (and one that is presumably more complex than null?). Alternatively, the table package can provide a predicate like valid-undefined-value?, which gets us right back where we started. -- Ashwin. -------  Received: from yale-bulldog by MC.LCS.MIT.EDU 30 Mar 86 00:33:23 EST Received: by Yale-Bulldog.YALE.ARPA; 27 Mar 86 11:49:29 EST (Thu) Date: 27 Mar 86 11:49:29 EST (Thu) From: Ashwin Ram Message-Id: <8603271649.AA03849@Yale-Bulldog.YALE.ARPA> Subject: Re: Tables To: Jonathan Young Cc: t-discussion@YALE.ARPA In-Reply-To: Jonathan Young , 25 Mar 86 14:31:11 EST (Tue) Weak Tables. A table is a list of associations - pairs of keys and values. If the key is garbage, i.e., is no longer accessible, I would like the association (i.e. the pointer to the value) to go away. This is not implementable in the current scheme. The tables used by OBJECT-HASH/OBJECT-UNHASH are weak tables, and it isn't too hard to implement similar tables for yourself if you really need them. I agree, however, that they should be part of the abstraction. Table Walking. It is desirable (occasionally) to apply a procedure to each pair in a table. This is possible in the current scheme only if you put a layer on top of the table package. Or if you used WALK-TABLE. Unreleased, but that never stopped me from using it. Before someone goes out and blindly writes a new table package, I'd like to hear more feedback. Are these idioms you use a lot? Are there other ideas you really need? Is this even the proper abstraction? --- Jonathan I think I agree with Rees ["I really wanted them to be extremely minimal, with very little structure. I wanted them to be as simple and primitive as pairs. They were to be viewed as primitive components out of which one could build higher-level abstractions"]. I think Scott's HT package is great (except that it doesn't implement weak tables), but I find it somewhat "big". I never use more than 25% of the functions provided. Since most can be built up on top of the 25% or so that are "really primitive" very easily in an particular application, my vote lies with a good abstraction that is reasonably "small". -- Ashwin. -------  Received: from yale-bulldog by MC.LCS.MIT.EDU 30 Mar 86 00:33:54 EST Received: by Yale-Bulldog.YALE.ARPA; 27 Mar 86 12:02:01 EST (Thu) Date: 27 Mar 86 12:02:01 EST (Thu) From: Ashwin Ram Message-Id: <8603271702.AA04000@Yale-Bulldog.YALE.ARPA> Subject: Re: Tables returning nil if no value To: Scott Turner Cc: t-discussion@YALE.ARPA In-Reply-To: Scott Turner , Wed, 26 Mar 86 11:28:56 PST I hesitate to offer an alternative to "the correct solution", but in our hash table (HT) package here at UCLA, we have nil as the undefined value and an additional function, HT:KEY? that returns true if the key is defined in the table (even with a nil value) and false otherwise. This has the advantage that you can ignore the defined/undefined issue if you'd like. In general, our solution has been to have the application (built on top of HT) decide about the defined/undefined question. I agree. My philosophy is always to let the user decide about the sticky issues, while providing a clean way to implement the outcome of the decision. ...The default hashing function is OBJECT-HASH, but the user can define another (as well as the equality predicate) in the call to HT:CREATE. This is also in concord with my philosophy. Provide nice defaults but never sacrifice extensibility. For the HT problem, the hashing and equality functions are the obvious examples of this. (I was surprised not to see functions in your list that get the hashing and equality functions for an HT.) The unobvious ones: HT:FIND-ENTRY -- returns the first pair that satisfies a predicate. HT:ADD/UPDATE -- add assumes the key is new, update the key is old. HT:FIND-ENTRY (along with HT:MAP) don't seem to make much sense. What does "the FIRST pair" mean? What significance would the order of entries returned by HT:MAP have? Entries in a table don't have any endogenous order. HT:WALK, by contrast, is fine (if you're into side-effects). It might be useful to make HT:MAP return a table (in the obvious way, so that (COPY ht) is just (HT:MAP IDENTITY ht)). -- Ashwin. -------  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 12:21:38 EST Received: from C.CS.CMU.EDU (c.cs.cmu.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 12:08:23 est Received: ID ; Mon 31 Mar 86 11:38:53-EST Date: Mon, 31 Mar 1986 01:51 EST Message-Id: Sender: FAHLMAN@C.CS.CMU.EDU From: "Scott E. Fahlman" To: Miller.pa@XEROX.COM Cc: Kahn.pa@XEROX.COM, scheme@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA Subject: non-list arguments In-Reply-To: Msg of 31 Mar 1986 01:19-EST from Miller.pa at Xerox.COM It certainly doesn't work in Common Lisp because lambda lists don't do destructuring in Common Lisp (though the argument lists for macros do destructure). Also, in Common Lisp you'd have to say "(function (lambda ...))". -- Scott  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 12:47:05 EST Received: from decwrl.DEC.COM (decwrl.dec.com.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 12:32:32 est Received: from magic.ARPA (magic) by decwrl.DEC.COM (4.22.03/4.7.34) id AA20193; Sun, 30 Mar 86 22:21:05 pst Received: by magic.ARPA (4.12/4.7.34) id AA06874; Sun, 30 Mar 86 22:22:02 pst From: ellis@decwrl.DEC.COM (John R. Ellis) Message-Id: <8603310622.AA06874@magic.ARPA> Date: 30 Mar 1986 2219-PST (Sunday) To: Ashwin Ram Cc: t-discussion@YALE.ARPA, Jonathan Young Subject: Re: Tables returning nil if no value In-Reply-To: Your message of 27 Mar 86 11:38:39 EST (Thu). <8603271638.AA03707@Yale-Bulldog.YALE.ARPA>  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 13:02:08 EST Received: from Xerox.COM (xerox.com.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 12:48:53 est Received: from Cabernet.ms by ArpaGateway.ms ; 30 MAR 86 22:19:17 PST Date: 30 Mar 86 22:19 PST From: Miller.pa@Xerox.COM Subject: non-list arguments To: scheme@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA Cc: Miller.pa@Xerox.COM, Kahn.pa@Xerox.COM Message-Id: <860330-221917-4500@Xerox> (apply (lambda (x . y) (+ x y)) (cons 1 2)) Does this nescesarily work in Scheme? How about T? Common-Lisp? (Example due to Ken Kahn)  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 13:08:06 EST Received: from Xerox.COM (xerox.com.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 12:50:29 est Received: from Cabernet.ms by ArpaGateway.ms ; 30 MAR 86 23:33:06 PST Date: 30 Mar 86 23:33 PST From: Miller.pa@Xerox.COM Subject: Re: non-list arguments In-Reply-To: "Scott E. Fahlman" 's message of Mon, 31 Mar 86 01:51 EST To: Fahlman@C.CS.CMU.EDU Cc: Miller.pa@Xerox.COM, Kahn.pa@Xerox.COM, scheme@MC.LCS.MIT.EDU, scheme%OZ@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA Message-Id: <860330-233306-4514@Xerox> It certainly doesn't work in Common Lisp because lambda lists don't do destructuring in Common Lisp (though the argument lists for macros do destructure). Also, in Common Lisp you'd have to say "(function (lambda ...))". OK, for Common Lisp how about: (apply #'(lambda (x &rest y) (+ x y)) (cons 1 2)) In other words, "&rest" is all the destructuring I need to ask this question. "." is simply the cleaner way one can write it in the Schemes. (Sorry for the redundant scheme mailing addresses. I'm having some mail returned and I don't know which address is causing the problem)  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 13:17:04 EST Received: from XX.LCS.MIT.EDU (xx.lcs.mit.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 13:08:58 est Received: from OZ.AI.MIT.EDU by XX.LCS.MIT.EDU via Chaosnet; 31 Mar 86 09:38-EST Date: 31 Mar 1986 09:33 EST (Mon) Message-Id: From: Bill Rozas To: Miller.pa@XEROX.COM Cc: Kahn.pa@XEROX.COM, scheme@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA Subject: non-list arguments In-Reply-To: Msg of 31 Mar 1986 01:19-EST from Miller.pa at Xerox.COM The Revised Revised Report on Scheme states that the second argument (2 argument form) to APPLY must be a "proper" list. Individual implementations are free to extend the semantics of APPLY. APPLY in MIT Scheme signals an error when given somthing other than a "proper" list.  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 14:02:32 EST Received: from C.CS.CMU.EDU (c.cs.cmu.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 13:34:55 est Received: ID ; Mon 31 Mar 86 13:08:26-EST Date: Mon, 31 Mar 1986 02:49 EST Message-Id: Sender: FAHLMAN@C.CS.CMU.EDU From: "Scott E. Fahlman" To: Miller.pa@XEROX.COM Cc: Kahn.pa@XEROX.COM, scheme%OZ@MC.LCS.MIT.EDU, scheme@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA Subject: non-list arguments In-Reply-To: Msg of 31 Mar 1986 02:33-EST from Miller.pa at Xerox.COM OK, for Common Lisp how about: (apply #'(lambda (x &rest y) (+ x y)) (cons 1 2)) Ah, I see what you're driving at now. No this is not guaranteed to work in Common Lisp in my opinion. The second argument to apply is a list of operands. In this case, you've got a list of one operand, 1, with a particularly ugly terminator, so the rest arg, Y, should end up bound to NIL. Some implementations may get this "right" by accident, but in most of them the Apply takes apart the operand list and simulates a call to the function. The lambda would be called with only one arg, and the rest arg would be NIL. The 2 has been discarded before the function ever gets called. -- Scott  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 14:32:48 EST Received: from MC.LCS.MIT.EDU (mc.lcs.mit.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 14:25:28 est Date: Mon, 31 Mar 86 04:05:03 EST From: Alan Bawden Subject: non-list arguments To: Miller.pa@XEROX.COM, Fahlman@C.CS.CMU.EDU Cc: SCHEME@MC.LCS.MIT.EDU, Kahn.pa@XEROX.COM, t-discussion@YALE.ARPA In-Reply-To: Msg of 30 Mar 86 22:19 PST from Miller.pa at Xerox.COM Message-Id: <[MC.LCS.MIT.EDU].866607.860331.ALAN> Date: 30 Mar 86 22:19 PST From: Miller.pa at Xerox (apply (lambda (x . y) (+ x y)) (cons 1 2)) Date: Mon, 31 Mar 1986 01:51 EST From: Scott E. Fahlman It certainly doesn't work in Common Lisp because lambda lists don't do destructuring in Common Lisp (though the argument lists for macros do destructure). Also, in Common Lisp you'd have to say "(function (lambda ...))". I would translate the question into Common Lisp as: (apply (function (lambda (x &rest y) (+ x y))) (cons 1 2)) which eliminates the question of "descructuring", but I would guess still preserves Ken Kahn's original question. A strict reading of the Common Lisp book would not require this to work, as far as I can see. An implementor would seem to be within his rights to insist that the last argument to APPLY always be a proper list.  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 16:02:18 EST Received: from MC.LCS.MIT.EDU (mc.lcs.mit.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 15:45:50 est Date: Sun, 30 Mar 86 16:23:54 EST From: Jonathan A Rees Subject: Tables returning nil if no value To: ram@YALE.ARPA Cc: t-discussion@YALE.ARPA, young-jonathan@YALE.ARPA In-Reply-To: Msg of 27 Mar 86 11:38:39 EST (Thu) from Ashwin Ram Message-Id: <[MC.LCS.MIT.EDU].866301.860330.JAR> Date: 27 Mar 86 11:38:39 EST (Thu) From: Ashwin Ram I would vote for a predicate TABLE-ENTRY? (like Scott's HT:KEY?) which checks whether K has an association in T. This sort of conflicts with my design which for (set (table-entry foo bar) '#f) deletes bar's entry in the table; if there's a possibility of having an entry of #f being different from no entry, then you have to have a separate deletion primitive. Things get out of hand quickly -- once you have one feature you want a zillion others. I say nip them in the bud. Jonathan.  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 17:17:33 EST Received: from LOCUS.UCLA.EDU (locus.ucla.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 17:12:52 est Date: Mon, 31 Mar 86 13:58:46 PST From: Uri Zernik To: t-discussion@YALE.ARPA Subject: please take me off the list Message-Id: <860331.215846z.04196.uri@SPHINX.LOCUS.UCLA.EDU> thanks, uri  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 31 Mar 86 17:22:11 EST Received: from MC.LCS.MIT.EDU (mc.lcs.mit.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 17:02:38 est Date: Mon, 31 Mar 86 16:52:27 EST From: Jonathan A Rees Subject: non-list arguments To: Fahlman@C.CS.CMU.EDU Cc: SCHEME@MC.LCS.MIT.EDU, Kahn.pa@XEROX.COM, Miller.pa@XEROX.COM, t-discussion@YALE.ARPA In-Reply-To: Msg of Mon 31 Mar 1986 01:51 EST from Scott E. Fahlman Message-Id: <[MC.LCS.MIT.EDU].867344.860331.JAR> Date: Mon, 31 Mar 1986 01:51 EST From: Scott E. Fahlman It certainly doesn't work in Common Lisp because lambda lists don't do destructuring in Common Lisp (though the argument lists for macros do destructure). Scheme and T don't have lambda list destructuring; they just use "." instead of "&rest". I haven't checked the manuals for T or Scheme but it was certainly the intent that the list passed to APPLY is unrelated to the list that a rest-parameter gets bound to. The rest-list should always be freshly consed, so e.g. the procedure LIST is equivalent to (LAMBDA X X). The last argument to APPLY must be a proper list. I think Common Lisp takes the same stance.  Received: from yale-bulldog by MC.LCS.MIT.EDU 31 Mar 86 18:30:50 EST Received: by Yale-Bulldog.YALE.ARPA; 31 Mar 86 18:11:20 EST (Mon) Date: 31 Mar 86 18:11:20 EST (Mon) From: Ashwin Ram Message-Id: <8603312311.AA12756@Yale-Bulldog.YALE.ARPA> Subject: Re: Tables returning nil if no value To: ellis@decwrl.DEC.COM (John R. Ellis) Cc: young@YALE-BULLDOG.YALE.ARPA, t-discussion@YALE.ARPA In-Reply-To: ellis@decwrl.DEC.COM (John R. Ellis), 30 Mar 1986 2224-PST (Sunday) If a table is used as a data structure common to two modules in a program, there is no a priori way for the one to know that an "undefined value" (as Ellis suggested) is in fact not a legitimate value stored in the table by the other. I don't understand. The Table package (interface, module, abstraction, ...) defines and exports a constant of unique type called UndefinedTableValue. By the contract of the interface, no one stores that value in the table (why should they?). Everyone knows for sure that UndefinedTableValue is not a legitimate table value. So there isn't any possiblity of confusing UndefinedTableValue with any other value. As I hinted at in my original message, the UndefinedTableValue solution is fine but reduces to the TABLE-ENTRY-EXISTS? solution. For consider what the program that is handed UndefinedTableValue in response to a TABLE-ENTRY call must do in order to detect that there was no proper value stored in the table under that key. It could either: a - Check that the returned value is *not* part of the co-domain of the function that the table implements, and hence is an "undefined table value", but writing (BELONGS-TO? V SOME-FUNCTIONAL-DOMAIN) is hard in general. b - Check that the returned value is the constant UndefinedTableValue (which is specified by the particular table package the user is using). However, (EQ? V 'UndefinedTableValue) reduces (i) portability of the code to other table packages, and (ii) transparency of the table implementation to the user program. Thus the user would need to "hide" the "constant of unique type" in an implementation-independent way, as follows: c - Define a predicate (UNDEFINED-TABLE-VALUE? V) which returns #t only to the constant UndefinedTableValue and #f to all other objects (by checking if V is EQ? to UndefinedTableValue). But this, of course, is identical to the TABLE-ENTRY-EXISTS? solution (which has the minor advantage of requiring one less function call). It would be nice if the table package provided this as part of the interface/module/abstraction for the reasons outlined in b above. -- Ashwin. -------  Received: from yale-bulldog by MC.LCS.MIT.EDU 31 Mar 86 18:59:34 EST Received: by Yale-Bulldog.YALE.ARPA; 31 Mar 86 18:45:15 EST (Mon) Date: 31 Mar 86 18:45:15 EST (Mon) From: Ashwin Ram Message-Id: <8603312345.AA13600@Yale-Bulldog.YALE.ARPA> Subject: Re: Tables returning nil if no value To: JAR@MC.LCS.MIT.EDU Cc: young@YALE-BULLDOG.YALE.ARPA, t-discussion@YALE.ARPA In-Reply-To: Jonathan A Rees , Sun, 30 Mar 86 16:23:54 EST Date: 27 Mar 86 11:38:39 EST (Thu) From: Ashwin Ram I would vote for a predicate TABLE-ENTRY? (like Scott's HT:KEY?) which checks whether K has an association in T. This sort of conflicts with my design which for (set (table-entry foo bar) '#f) deletes bar's entry in the table; if there's a possibility of having an entry of #f being different from no entry, then you have to have a separate deletion primitive. Things get out of hand quickly -- once you have one feature you want a zillion others. I say nip them in the bud. Jonathan. In practical terms I agree with you. I've been using tables (and even property lists) for a long time without ever being bothered by the "nil vs. doesn't-exist" distinction. In the few cases where it matters, it's easy enough to write a couple of one-liners to handle the situation. For the same reason I'm quite happy with ASS returning nil for non-existent entries and a cons cell otherwise, and using these interchangeably as boolean and list values. In the case of tables, however, a strong (theoretical) case could be made for having a separate TABLE-ENTRY? predicate (along with the REMOVE-TABLE-ENTRY primitive it necessitates). I expect to hear a million voices claiming that they would like to be able to store nil (or #f) explicitly in a table as a value in its own right. Making (set (table-entry tbl key) '#f) automatically delete the entry may be problematic (for a sample, what is the size of the table after you've entered one #t and five #f's into it? One or six? What if you now set the one #t entry to #f? Do you now have an empty table?) One of these days we'll move on to three-valued logics and then everyone will be happy :-). -- Ashwin. -------  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 1 Apr 86 09:37:50 EST Received: from MC.LCS.MIT.EDU (mc.lcs.mit.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 14:25:28 est Date: Mon, 31 Mar 86 04:05:03 EST From: Alan Bawden Subject: non-list arguments To: Miller.pa@XEROX.COM, Fahlman@C.CS.CMU.EDU Cc: SCHEME@MC.LCS.MIT.EDU, Kahn.pa@XEROX.COM, t-discussion@YALE.ARPA In-Reply-To: Msg of 30 Mar 86 22:19 PST from Miller.pa at Xerox.COM Message-Id: <[MC.LCS.MIT.EDU].866607.860331.ALAN> Date: 30 Mar 86 22:19 PST From: Miller.pa at Xerox (apply (lambda (x . y) (+ x y)) (cons 1 2)) Date: Mon, 31 Mar 1986 01:51 EST From: Scott E. Fahlman It certainly doesn't work in Common Lisp because lambda lists don't do destructuring in Common Lisp (though the argument lists for macros do destructure). Also, in Common Lisp you'd have to say "(function (lambda ...))". I would translate the question into Common Lisp as: (apply (function (lambda (x &rest y) (+ x y))) (cons 1 2)) which eliminates the question of "descructuring", but I would guess still preserves Ken Kahn's original question. A strict reading of the Common Lisp book would not require this to work, as far as I can see. An implementor would seem to be within his rights to insist that the last argument to APPLY always be a proper list.  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 1 Apr 86 09:45:58 EST Received: from C.CS.CMU.EDU (c.cs.cmu.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 12:08:23 est Received: ID ; Mon 31 Mar 86 11:38:53-EST Date: Mon, 31 Mar 1986 01:51 EST Message-Id: Sender: FAHLMAN@C.CS.CMU.EDU From: "Scott E. Fahlman" To: Miller.pa@XEROX.COM Cc: Kahn.pa@XEROX.COM, scheme@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA Subject: non-list arguments In-Reply-To: Msg of 31 Mar 1986 01:19-EST from Miller.pa at Xerox.COM It certainly doesn't work in Common Lisp because lambda lists don't do destructuring in Common Lisp (though the argument lists for macros do destructure). Also, in Common Lisp you'd have to say "(function (lambda ...))". -- Scott  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 1 Apr 86 09:53:25 EST Received: from C.CS.CMU.EDU (c.cs.cmu.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 13:34:55 est Received: ID ; Mon 31 Mar 86 13:08:26-EST Date: Mon, 31 Mar 1986 02:49 EST Message-Id: Sender: FAHLMAN@C.CS.CMU.EDU From: "Scott E. Fahlman" To: Miller.pa@XEROX.COM Cc: Kahn.pa@XEROX.COM, scheme%OZ@MC.LCS.MIT.EDU, scheme@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA Subject: non-list arguments In-Reply-To: Msg of 31 Mar 1986 02:33-EST from Miller.pa at Xerox.COM OK, for Common Lisp how about: (apply #'(lambda (x &rest y) (+ x y)) (cons 1 2)) Ah, I see what you're driving at now. No this is not guaranteed to work in Common Lisp in my opinion. The second argument to apply is a list of operands. In this case, you've got a list of one operand, 1, with a particularly ugly terminator, so the rest arg, Y, should end up bound to NIL. Some implementations may get this "right" by accident, but in most of them the Apply takes apart the operand list and simulates a call to the function. The lambda would be called with only one arg, and the rest arg would be NIL. The 2 has been discarded before the function ever gets called. -- Scott  Received: from yale-bulldog by MC.LCS.MIT.EDU 1 Apr 86 16:25:07 EST Received: by Yale-Bulldog.YALE.ARPA; 1 Apr 86 12:20:32 EST (Tue) Date: 1 Apr 86 12:20:32 EST (Tue) From: Larry Hunter Message-Id: <8604011720.AA06892@Yale-Bulldog.YALE.ARPA> Subject: Nil v. UndefinedTableValue To: t-discussion@YALE.ARPA After bringing up the issue and listening (?) to the various replies, I find myself inclined to side with Rees and retract my initial wish. In situations where I want to know if an entry has been actually set to nil, there are a variety of approaches I can use on top of the vanilla package (eg, maintain a list of keys as a table entry, cons each entry to some symbol thereby simulating multiple value return, etc). If I don't care, I can use the vanilla package. I have been doing this all along, and, given T's philosophy of providing the minimum sufficient functionality and leaving the driving to us, I don't see any compelling reason to change. My comments about having hooks for providing hashing and equality functions still stand, tho. Larry -------  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 1 Apr 86 17:17:13 EST Received: from MIT-ZERMATT.ARPA (mit-zermatt.arpa.ARPA) by yale-cheops.YALE.ARPA; Tue, 1 Apr 86 17:01:10 est Received: from ASPEN.LCS.MIT.EDU by MIT-ZERMATT.ARPA via CHAOS with CHAOS-MAIL id 29890; Tue 1-Apr-86 15:27:29-EST Date: Tue, 1 Apr 86 15:26 EST From: Robert Halstead Subject: non-list arguments To: JAR@MIT-MC.ARPA Cc: SCHEME@MIT-MC.ARPA, t-discussion@YALE.ARPA In-Reply-To: <[MC.LCS.MIT.EDU].867344.860331.JAR> Message-Id: <860401152644.7.RHH@ASPEN.LCS.MIT.EDU> I haven't checked the manuals for T or Scheme but it was certainly the intent that the list passed to APPLY is unrelated to the list that a rest-parameter gets bound to. The rest-list should always be freshly consed, so e.g. the procedure LIST is equivalent to (LAMBDA X X). The last argument to APPLY must be a proper list. I think Common Lisp takes the same stance. A quick scan of the Common Lisp book leaves the question unresolved; maybe Guy Steele could comment. However, I have seen object-oriented programs where this would probably lead to less than the most efficient implementation. Suppose we represent objects by procedures and call them using the general form ( ) where the indicates the operation to be performed on and (possibly empty) consists of operation-dependent parameters. One way to code up such an object is as (lambda (key . rest) (cond ((eq? key 'foo) (apply f1 rest)) ((eq? key 'bar) (apply f2 (cons 'barbar rest))) ...)) where we use the key to pick a function (or new object) to forward the request to, on the assumption that somebody at the end of the chain will actually use the rest of the original arguments. Putting an extra list copy in at each forwarding step seems mildly expensive and somewhat unnecessary. I don't think that LAMBDA should be prohibited from checking that its argument is a true list, or from copying it over, but I also don't think it should be required to. Why is it important for the list of rest arguments to be copied over when we don't, for example, expect quoted lists to be copied over every time an expression '(...) is evaluated? To summarize, I think it should be permissible for (eq? ((lambda x x) l) l) to return true, but it should not be a requirement. Furthermore, it should be permissible for an implementation to report an error if l in the above expression is not a true list, but an implementation should not be required to do so. Of course, it would still be true that ((lambda x x) 3 4 5) would return a freshly consed list, just like (list 3 4 5). An interesting question: do people expect (apply list l) to return a top-level copy of l? -b.  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 2 Apr 86 02:58:39 EST Received: from C.CS.CMU.EDU (c.cs.cmu.edu.ARPA) by yale-cheops.YALE.ARPA; Mon, 31 Mar 86 12:08:23 est Received: ID ; Mon 31 Mar 86 11:38:53-EST Date: Mon, 31 Mar 1986 01:51 EST Message-Id: Sender: FAHLMAN@C.CS.CMU.EDU From: "Scott E. Fahlman" To: Miller.pa@XEROX.COM Cc: Kahn.pa@XEROX.COM, scheme@MC.LCS.MIT.EDU, t-discussion@YALE.ARPA Subject: non-list arguments In-Reply-To: Msg of 31 Mar 1986 01:19-EST from Miller.pa at Xerox.COM It certainly doesn't work in Common Lisp because lambda lists don't do destructuring in Common Lisp (though the argument lists for macros do destructure). Also, in Common Lisp you'd have to say "(function (lambda ...))". -- Scott  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 3 Apr 86 10:47:16 EST Received: from GODOT.THINK.COM (godot.think.com.ARPA) by yale-cheops.YALE.ARPA; Thu, 3 Apr 86 10:35:10 est Received: from katherine by GODOT.THINK.COM via CHAOS; Thu, 3 Apr 86 10:34:56 est Date: Thu, 3 Apr 86 10:36 EST From: Guy Steele Subject: non-list arguments To: rhh@MIT-VAX.ARPA, JAR@MIT-MC.ARPA Cc: SCHEME@MIT-MC.ARPA, t-discussion@YALE.ARPA, gls@THINK-AQUINAS.ARPA In-Reply-To: <860401152644.7.RHH@ASPEN.LCS.MIT.EDU> Message-Id: <860403103623.3.GLS@THINK-KATHERINE.ARPA> I haven't checked the manuals for T or Scheme but it was certainly the intent that the list passed to APPLY is unrelated to the list that a rest-parameter gets bound to. The rest-list should always be freshly consed, so e.g. the procedure LIST is equivalent to (LAMBDA X X). The last argument to APPLY must be a proper list. I think Common Lisp takes the same stance. A quick scan of the Common Lisp book leaves the question unresolved; maybe Guy Steele could comment. This question came up recently on the Common-Lisp mailing list. The unofficial consensus, as I understood it, was that the book is vague on this point and requires correcting; that the last argument to APPLY should be a proper list; and that a list passed as an argument to APPLY might or might not share list structure with an eventual &REST argument resulting from the application. --Guy  Received: from yale-cheops.YALE.ARPA by MC.LCS.MIT.EDU 4 Apr 86 02:17:51 EST Received: from GODOT.THINK.COM (godot.think.com.ARPA) by yale-cheops.YALE.ARPA; Thu, 3 Apr 86 10:35:10 est Received: from katherine by GODOT.THINK.COM via CHAOS; Thu, 3 Apr 86 10:34:56 est Date: Thu, 3 Apr 86 10:36 EST From: Guy Steele Subject: non-list arguments To: rhh@MIT-VAX.ARPA, JAR@MIT-MC.ARPA Cc: SCHEME@MIT-MC.ARPA, t-discussion@YALE.ARPA, gls@THINK-AQUINAS.ARPA In-Reply-To: <860401152644.7.RHH@ASPEN.LCS.MIT.EDU> Message-Id: <860403103623.3.GLS@THINK-KATHERINE.ARPA> I haven't checked the manuals for T or Scheme but it was certainly the intent that the list passed to APPLY is unrelated to the list that a rest-parameter gets bound to. The rest-list should always be freshly consed, so e.g. the procedure LIST is equivalent to (LAMBDA X X). The last argument to APPLY must be a proper list. I think Common Lisp takes the same stance. A quick scan of the Common Lisp book leaves the question unresolved; maybe Guy Steele could comment. This question came up recently on the Common-Lisp mailing list. The unofficial consensus, as I understood it, was that the book is vague on this point and requires correcting; that the last argument to APPLY should be a proper list; and that a list passed as an argument to APPLY might or might not share list structure with an eventual &REST argument resulting from the application. --Guy  Received: from yale-bulldog by MC.LCS.MIT.EDU 4 Apr 86 16:20:25 EST Received: by Yale-Bulldog.YALE.ARPA; 4 Apr 86 12:05:25 EST (Fri) Date: 4 Apr 86 12:05:25 EST (Fri) From: Ashwin Ram Message-Id: <8604041705.AA18731@Yale-Bulldog.YALE.ARPA> Subject: Kudos To: t-discussion@YALE.ARPA What do you think this will return (i.e., T or NIL): (= (factorial 1999) (/ (factorial 2000) 2000)) where FACTORIAL is the obvious non-tail-recursive implementation of the factorial function? (Remember that (factorial 2000) is a VERY big number.) Well, I tried it. After three garbage collections, it finally returned with --- did you guess it? --- T !!! Hats off to the T implementors! Ashwin. -------