TULSA@MIT-MC 03/23/83 13:09:06  PAULD@MIT-AI 02/18/83 20:05:50 To: T at MIT-AI  To: Whom It May Concern From: KMP Re: File contents This file is a transcript of the Yale Scheme discussion. It is provided so that MIT people can have a way of viewing the discussion. It is requested that MIT people not already on the list not send mail directly to the T-Discussion. If you have something to say, send it to KMP or JAR and we'll forward it if appropriate to the list. This may sound ruthless, but it keeps the list from being deluged with hopeless amounts of flamage. -kmp  Date: 11 April 1982 14:40-EST From: Kent M. Pitman To: T-DISCUSSION-TRANSCRIPT at MIT-MC This is a test.  Date: Wednesday, 14 April 1982 10:27-EST From: Jonathan Rees To: Tk at MIT-AI, Danny at MIT-AI, Kmp at MIT-MC, Hanson at MIT-AI Cc: T-Discussion-Transcript at MIT-MC Subject: MC: LSPMAI; T MAIL I have added T-DISCUSSION-TRANSCRIPT@MIT-MC to Yale's T-DISCUSSION distribution list. So if you want to see "announcements", follow discussions, read flames, etc., check the file MC: LSPMAI; T MAIL periodically. I'll also send over older messages at some point (can't get an FTP connection at the moment); probably I'll BABYLize them and put them in LSPMAI; somewhere. Will send you another message when this is accomplished.  Date: 14-Apr-82 12:28PM-EST (Wed) From: Drew McDermott Subject: magic? aberration To: Rees at YALE Cc: T-Discussion at YALE I understood that magic? was working correctly-- hence my chuckle. I sympathize with your decision not to allow magic things as variable values. However, it leads to the awkwardness described. I predict this awkwardness will come back to haunt you. E.g., a list of objects cannot be stepped through if it has a magic element. All magic objects will behave like the "unbound object" in ILISP. You can do anything you like with it, except set it to a variable in interpreted code. This leads to unbelievable contortions in some ILISP programs. I fear the contortions will be much more frequent in T programs. I have a counter-proposal: 1) Allow magic things anywhere 2) If a "processor" (interpreter, e.g.) sees (x ...), and x evaluates to a magic object, then x must be the standard name of the object. The compiler will never detect this situation, of course, but the code it produces could. So (LET ((X COND)) (X ...)) blows up when X is called, in both interpreted and compiled code, because X is not the standard name of its value. This covers all the cases I can think of, but I can only think of two. -------  Date: Wednesday, 14 April 1982 13:32-EST From: Jonathan Rees To: Mcdermott at YALE Cc: T-Discussion at YALE Subject: MAGIC? - no aberration From: Drew McDermott Re: magic? aberration ... E.g., a list of objects cannot be stepped through if it has a magic element. All magic objects will behave like the "unbound object" in ILISP.... Sorry, you got it all wrong. My explanations must be much more opaque than I imagine when I write them. Magic objects ARE normal things. There's no problem setting (interpreter) variables to them, stepping through lists of them, or doing anything else to them; there's nothing "magical" about them at all. The only funniness is the way in which they are associated (bound) with identifiers. In effect, the variable's "value cell" has, in addition to its value slot, a flag (bit) which says whether or not there's a value there. If there's no value there, we can use the value slot to hold any interesting object we want, for example a "magic object". Magic objects do NOT look like "unbound things"; you can pass them around with impunity. No such illegal "unbound objects" exist. (As I hinted in a previous message, the implementation doesn't actually go like this; but it might as well.) I hope that with this reassurance I don't need to argue against your proposal, which completely goes against the grain of T, where things don't know and don't care about their names, except for debugging purposes. I don't understand what awkwardness you refer too, unless it's the need for extra special forms for fetching and setting the "magic bindings" of variables (i.e., hacking the values as usual, but forcing the has-value bit the wrong way); I think this is a reasonable price to pay.  Date: Wednesday, 14 April 1982 14:29-EST From: Jonathan Rees To: T-Discussion at YALE Subject: Version 0.53 released I just released version 0.53. A few minor bugs fixed. A preliminary version of a new routine, "GC", is there, but it hasn't been thoroughly tested. Its purpose is to reclaim unused storage. Its main drawback at the moment is that it blows up the SECOND time you call it. Hopefully this will be fixed shortly. It does a LOT of metering and redundant error-checking, and of course the compiler's code generator needs a lot of work, so it's a lot slower than it ought to be. And it probably prints out more statistics and debugging info than you'd like to know (but you can set *GC-DEBUG?* to () if you want). So I wouldn't say that it's "released". I'll let you know when it's in better shape. Report problems.  Date: Thursday, 15 April 1982 17:38-EST From: Jonathan Rees To: T-Discussion at YALE Subject: improvements I hereby release the GC, and challenge people to find bugs in it. My previous apologies still apply. It's dreadfully slow, and its output is overly verbose. But it does seem to work, and apparently you can now call it more than once. (Thanks to Dave Miller for bringing this to my attention.) At some point I'll make it invoke itself automagically. For now you need to invoke it explicitly, by saying (GC). Don't do it inside an error break loop (or a ^C breakpoint); it will deride you for doing so, and may not complete successfully. More info later on how to find out how big the heap is, and other information to help you decide when it's a good time to GC. Another new feature, installed by popular demand, is PP - a pretty-printer, of sorts. Say (PP FOO), where FOO is (an expression evaluating to) an interpreted procedure or an s-expression. PP suffers from the following defects, which will be fixed within the next few days: - It doesn't indent. Lines come out properly broken, but left-justified. - It won't work on macros. Eventually one will be able to say (PP FOO) even if (DEFINE-MACRO (FOO ...) ...). - It uses the stupidest possible n^2 algorithm, so it's slow. I encourage people to use the system. I'm a little disappointed in the level of interest. I bet no one has even tried running the compiler. The system runs on the Apollo (including FASLOAD), and will soon be available as a normal "tools" program. I don't know what you're waiting for. (Manual? Structures? Non-cross-compiler? Why wait - you got two helpful consultants; entities (and vectors); and a cross-compiler.)  Date: Friday, 16 April 1982 12:36-EST From: Jonathan Rees To: Mcdermott at YALE Cc: T-Discussion at YALE Subject: Using t Date: 16-Apr-82 10:50AM-EST (Fri) From: Drew McDermott To: Rees Re: Using t 1) Will read, write, etc. eventually have optional stream args? (Sure would be useful.) Right now the stream arg is required. To make this a little easier to bear there are variables SO (= STANDARD-OUTPUT) and SI (= STANDARD-INPUT). (This is not an "official feature" - names subject to change.) E.g. (READ SI), (PRINT FROB SO). Eventually you may be able to say (READ) and (PRINT FROB) but not until the compiler can handle "optional" arguments in an efficient way, which it can't right now. 2) We couldn't get BIND to work. The error message concerned an undefined procedure or something. The example was (BIND ((Y 5)) Y). It used to work. I'll look into it. 3) Will there ever be upper-lower case flexibility? We have decided this isn't really urgent,but would be useful. If it gets implemented, it would be nice to have 3 modes: force to upper, force to lower, and switch. (How hard would it be for us to implement this?) New version of reader to be released soon has a parameter *TRANSLATE-CONSTITUENT*. (For an explanation of the term "constituent" see the Common Lisp manual.) Its default value is CHAR-UPCASE (coerce to upper case) but you can set it to ID (no coercion) or CHAR-DOWNCASE. ---------- Helpful hints: To implement / as the escape character, and disable \: (SET-SYNTAX #\/ (SYNTAX #\\)) (SET-SYNTAX #\\ (SYNTAX #\X)) To implement ! as a dispatching read macro, like #: (SET-SYNTAX #\! (MAKE-DISPATCH-READ-MACRO)) To make !\ read in the same as LAMBDA: (SET-DISPATCH-SYNTAX (SYNTAX #\!) #\\ (LAMBDA (STREAM CHAR ARG) (IGNORE STREAM CHAR ARG) 'LAMBDA))  Date: Monday, 19 April 1982 16:02-EST From: Jonathan Rees To: T-Discussion at YALE Subject: Release notice: T version 0.54 on Vax Just what you've all been waiting for... New features: - Faster startup. Now fasloads only one file, not 18. - REM-PROPERTY (a.k.a. REM) exists. Sort of like conventional REMPROP. - Some math functions (COS, SIN, EXP, LOG, SQRT, ...) are available. See BRIEF.DOC. - The VAR-MAGIC special form seems to work. Bugs fixed: - BIND and MAP have been fixed. - PP works on macros. (To the extent it works at all.) - Doing a BACKTRACE inside a memory protection error, or inside a ^C out of T code, now seems to work.  Date: Wednesday, 21 April 1982 15:09-EST From: Jonathan Rees To: T-Discussion at YALE Subject: enhancements For all you hackers out there, more features... this about takes me to the end of things I can do without making some kind of structure package & a manual... so don't be too distressed about how random this all is... - Read-macro characters don't act as break characters. For example: (SET-SYNTAX #\? (LAMBDA (STREAM CH) `(QUESTION-MARK ,(READ STREAM)))) With this definition, ?FOO reads in as (QUESTION-MARK FOO), but FOO? still reads in as the single symbol FOO?. - (MDEBUG) puts you in a read-macroexpand-prettyprint loop. Very handy if you're debugging macros. Type any atom to exit. This is likely to be replaced by a fancier facility in the future, but for now, it'll do. (There is a MACRO-EXPAND routine but I'll only describe it if someone asks about it.) - General I/O streams seem to work. Soon PP will start indenting, and (FORMAT NIL ...) will work. Even without these, see what you get: - (STRING->STREAM string) returns a stream from which you can READ or READC or whatever. (LET ((Z (STRING->STREAM "What (a win) "))) (LIST (READ Z) (READ Z))) => (WHAT (A WIN)) - (WITH-OUTPUT-TO-STRING var . body) binds var to an output stream to which you can do WRITEC, PRINT, DISPLAY, FORMAT, etc. Output is accumulated in a string, which is yielded as the value of the whole form. E.g. (WITH-OUTPUT-TO-STRING FOO (WRITES FOO "What ") (PRINT '(A WIN) FOO) (WRITEC FOO #\.)) => "What (A WIN)." - You can define your own streams using ENTITY-expressions. See STREAMS.TAU for examples. Documentation forthcoming.  Date: 2-May-82 6:42PM-EDT (Sun) From: John O'Donnell Subject: T manual To: T-Discussion at YALE Our heroes have made great progress on the manual front. In the next week or so there'll probably be a draft version suitable for distribution to the interested. Send mail to me if you want a copy. -------  Date: Monday, 3 May 1982 16:02-EDT From: Jonathan Rees To: Odonnell at YALE Cc: Adams at YALE, T-Discussion at YALE Subject: [Riesbeck: Re: Speed comparisons] Date: 3-May-82 2:00PM-EDT (Mon) From: Chris Riesbeck Subject: Re: Speed comparisons how will things slow down when the garbage collector is added The question is, how long will garbage collections take, and how often will they happen. I don't have good answers to these questions; all I can say is that (a) because of larger address space and more compact data structures, one will probably be able (and want) to do more consing (twice as much? six times as much?) between GC's than one does in DEC-20 lisps; (b) this is offset by the fact that the interpreter conses a lot, but this may change - see below; (c) garbage collection will "take a long time" (like half as much time as it does now on the VAX), in spite of projected compiler & system improvements (see below), until either I recode the GC in assembler or I get about 5 months to REALLY bring the quality of compiled code up to that of, say, BLISS-11's. how much consing can be removed from interpreted code I think most of it can be eliminated, using a variety of techniques. The current interpreter is still a very rough cut. The main things that can be done include: better handling of "entities" in the compiler (cutting by at least half the consing currently required to make interpreted closures); specialized interpreters for things now implemented as macros, like AND and OR; and stack-allocated environments, accomplished by some combination of (a) more static code analysis (ugh) and (b) dynamic "analysis" of the sort described by McDermott at the 1980 Lisp Conference. how much faster can the scanner get This I don't know, but I expect a factor of 2 to 3 when the compiler gets a little better, and maybe another factor of 2 to 3 when I've developed some profiling tools to find out what the bottlenecks are, and tuned the code accordingly. will it be the case that the interpreted form of compiled code will be available for prettyprinting? if not, i would expect far more code to stay interpreted than you do -- that's why it stays interpreted on the 20, not that most code won't compile I think it's pointless to leave the source code lying around in your Lisp as S-expression, regardless of whether it's interpreted or compiled, when it's sitting out there in a much more readable form in some file in your editor. In Maclisp, it takes fewer characters for me to get from lisp to the definition of some routine inside EMACS than it would for me to ask Maclisp to pretty-print the routine: control-N escape . routine-name return, versus open GRINDEF [or PP] space routine-name close. And the result is so much more satisfying. This sort of facility (hopefully even smoother than Maclisp's - more like the Lisp Machine's) is high on my list of things to do - but it may end up being easier on the VAX than on the Apollo. I'm surprised you don't do this with TLISP and Z. Anyhow, a general note about efficiency... I think the main thing right now that makes it all so slow is compiler problems. I intend to improve this situation in several phases, the first of which should occupy about half of my summer and bring about a factor of 2 to 3 speedup. Tuning (of which there has been none) should also be a big help.  Date: 3-May-82 4:27PM-EDT (Mon) From: Nathaniel Mishkin Subject: Re: [Riesbeck: Re: Speed comparisons] To: Rees at YALE Cc: T-Discussion at YALE In-Reply-To: Your message of Monday, 3 May 1982 16:02-EDT will it be the case that the interpreted form of compiled code will be available for prettyprinting? if not, i would expect far more code to stay interpreted than you do -- that's why it stays interpreted on the 20, not that most code won't compile This sort of facility (hopefully even smoother than Maclisp's - more like the Lisp Machine's) is high on my list of things to do - but it may end up being easier on the VAX than on the Apollo. I'm surprised you don't do this with TLISP and Z. I'm really hardpressed to believe that the reason people don't compile TLISP is because of prettyprinting problems. As far as the desired interface being harder on the Apollo, I think we should stop thinking in terms of the fairly gross (but useful) hacks done to get Maclisp and Emacs to interface well. Geez, all you need is another window with the file containing the definitions in it. If you're really hooked on gross interfaces, T will surely be able to do the equivalent gross things by "stuffing" display manager commands. -- Nat -------  Date: 3-May-82 4:43PM-EDT (Mon) From: Chris Riesbeck Subject: minutiae To: T-Discussion at YALE As I work on the Apollo T, you will be seeing a lot of trivia like this from me: LIST?, as opposed to CARCDRABLE?, should see if the top-level really is a list, i.e., terminates in NIL, so that anything that passes the LIST? test can be passed to LENGTH, MAP, etc. is there anyway to find, or at least close, the input file after LOAD hits EOF in the middle of an expression? a CLOSE-ALL (called by RESET automatically perhaps) or a *MOST-RECENT-STREAM* would be useful. right now, if that happens, I can't correct and save the file without first killing the T process. why isn't SYMBOLCONC spelled SYMBOL-CONC? -------  Date: Monday, 3 May 1982 16:57-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: minutiae 1. I think you want to use PROPER-LIST? to check how the supposed list ends. 2. Try (CLOSE *LOAD-CHANNEL*) until I make things work right or at least better. 3. The name SYMBOLCONC came out of history, and belongs there. I would love to give it a better name but can't think of one I really like. In such situations (and there are many) I stick with something idiosyncratic and absurd rather than go for something that might imply non-existent consistency or otherwise be misleading. By current conventions, calling it SYMBOL-CONC would sort of imply that there is such a thing as CONC, and there isn't.  Date: 7-May-82 4:46PM-EDT (Fri) From: Chris Riesbeck Subject: string functions To: T-Discussion at YALE It seems to be agreed that T will need some decent string functions and top on my list is a substring function. UCILisp has one which I like a lot: (SUBSTRING string m n) takes a substring of string from m to n. Note that this is not interpreted as taking n characters starting from position m. UCILisp used to do that, and it loses. But even better is that UCILisp allows m and n to be negative, in which case they count from the right. The most common use of this is (SUBSTRING string 1 -1) which strips off the last character. Us natural language-hackers really appreciate that. Without it, you are constantly grabbing the string length so you can decrement it. The problem? This conflicts with 0-based indexing, unless you allow -0 to be different than 0, a bag of worms I assume no one wants to open. A solution? Abandon 0-based for substring -- the -1 feature is just too useful. Any other ideas? -------  Date: 7-May-82 4:49PM-EDT (Fri) From: Chris Riesbeck Subject: substrings To: T-Discussion at YALE oooops -- that should have been (SUBSTRING string 1 -2). -------  Mail-from: ARPANET site PARC-MAXC rcvd on Fri May 7 17:09:22 Date: 7 May 1982 14:05 PDT From: Deutsch at PARC-MAXC Subject: Re: string functions In-reply-to: Riesbeck's message of 7-May-82 4:46PM-EDT (Fri) To: Chris Riesbeck cc: T-Discussion at YALE Does (SUBSTRING string m n) mean character m THROUGH n or character m UP TO n? In Interlisp it means the former. If you choose the former, it turns out to be useful for various boundary cases for (SUBSTRING string m m-1) to deliver the null string. This allows 0 to mean the left end, i.e. (SUBSTRING string 1 0) is null. But it doesn't give any representation for the right end. I think I favor the "up to" interpretation. Given the choice, I would prefer to keep 0-based indexing and pitch the negative indexing feature. [*** begin flame ***] Interlisp is full of little features where some argument to some function has six different interpretations depending on whether it is a positive integer, negative integer, NIL, T, atom, list, etc. The problem with these "features" is that (1) they slow down all the primitives with extra checks all the time, whether you use the features or not. (2) they reduce error-checking -- if your program thinks it's computed a positive string index and it turns out to be negative, you get some unexpected result instead of the error indication you wanted. (3) they make understanding programs (both humanly and mechanically) harder because you have to do case analyses all the time. Features of this kind look like creature comforts, but they wind up making life harder in the long run. [*** end flame ***] "Opinions are like assholes: everybody has one."  Date: 7-May-82 5:28PM-EDT (Fri) From: Chris Riesbeck Subject: Re: string functions To: Deutsch at PARC-MAXC Cc: T-Discussion at YALE In-Reply-To: Your message of 7 May 1982 14:05 PDT (SUBSTRING string m n) means m THROUGH N, and -1 means the right end. I agree that too many features spoil the broth, especially of the "T means this, NIL means this, and no argument at all means this" variety. What I want is a convenient way to reference the right end. When I compare both convenience AND READABILITY of (SUBSTRING string 0 (- (STRING-LENGTH string) 2)) with (SUBSTRING string 1 -2) I know where my vote goes. With 1-based indexing, I can read the second form as "from first to second-last". I have no easy way to read the first 0-based form. Perhaps there's a totally different way to look at this, such as (SUBSTRING string (LEFT-INDEX m) (RIGHT-INDEX n)) or something. -------  Date: Friday, 7 May 1982 18:19-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: Substrings T will support the following feature: if the second argument to ADD (i.e. +) is a list consisting of a single number, then ADD will multiply its first argument by that number, and return the result. But seriously... I agree with Riesbeck that substring-from-end is very useful, and I agree with Deutsch that there shouldn't be overloading, and that consistent zero-originality is important. So what's wrong with (SUBSTRING string start end) and (SUBSTRING-FROM-END string start-from-end end-from-end) with the invariant (SUBSTRING-FROM-END s x y) <=> (STRING-REVERSE (SUBSTRING (STRING-REVERSE s) x y)) Consistent with Lisp Machine Lisp and Common Lisp (neither of which, much to my surprise, has documented anything corresponding to SUBSTRING-FROM-END), and also consistent with my preference for half-open intervals (reflected all over the place inside T already), the "end" refers to the index of the first character not selected. (SUBSTRING "Feap" 0 3) => "Fea" (SUBSTRING-FROM-END "Feap" 0 3) => "eap" (SUBSTRING "Feap" 1 2) => "e" (SUBSTRING-FROM-END "Feap" 1 2) => "a" (If SUBSTRING-FROM-END is too long, how about GNIRTSBUS?) There is the question of whether the substring should be shared... T is kind of schizophrenic on the question of whether strings are to be considered mutable objects; shared substrings are quite efficient, but ya gotta be careful. I need to think about this some more. It's especially hairy because string headers are mutable independently of the block of characters they point into.  Date: 7-May-82 6:56PM-EDT (Fri) From: John R. Ellis Subject: Re: Substrings To: Rees at YALE Cc: T-Discussion at YALE In-Reply-To: Rees's message of Friday, 7 May 1982 18:19-EDT Here is my asshole: ...and also consistent with my preference for half-open intervals (reflected all over the place inside T already), Hear here. Half-open intervals are God's gift to programmers, especially when you have more than one. I like SUBSTRING and SUBSTRING-FROM-END; say what you mean and mean what you say. There is the question of whether the substring should be shared... T is kind of schizophrenic on the question of whether strings are to be considered mutable objects; shared substrings are quite efficient, but ya gotta be careful. I need to think about this some more. It's especially hairy because string headers are mutable independently of the block of characters they point into. If T is going to be a system's programming language, it really needs both for applications doing heavy string processing (e.g. the U editor), until such time as GC and memory are no longer a worry (Ha!). And the semantics of strings ought to be explicit-- i.e. a string has two parts, a header and some text, the header has a length, the text may be shared, etc. One way of making shared substrings easier to program with is to have two different kinds of strings-- strings, which have their "own" text, and substrings, which share the text of some other string or substring. Both have the same set of operations on them. That way, the program and the programmer can distinguish what is shared and what isn't. -------  Date: Friday, 7 May 1982 22:48-EDT From: Jonathan Rees To: T-Discussion at YALE Cc: GUY.STEELE at CMU-10A Subject: Oh no, it's the start/end versus start/count controversy Well, we've gotta decide what to do about the start/end versus start/count problem. Maybe this is a matter of religion but somehow we've got to cope with it. I agree with whoever it was who recently said here that we want to support both options; but this won't come easily. The problem is names. To review, the problem is with things like SUBSEQ, SUBSTRING, and SUBBITV. (A BITV is a bit-vector; ignore that choice of type name for now, that's also up in the air.) When extracting a sub-sequence, do we designate the range to be extracted by giving the start element index and end index, or by a start index and a count of the number of elements to be extracted? (Note that zero-origin is definitely decided upon, and also that in the start/end case, the end is the index of the first element not selected, not that of the last element selected.) The Common Lisp "committee," and the NIL "committee" before that, discussed this question at length. NIL decided on start/count, Common Lisp (and Lisp Machine) on start/end. Start/count is nicer for hardware like the VAX which prefers things in that form, and is also nicer for things like bit vectors where you often want to extract a field of known width. However, the Lisp Machine people are adamant that start/end is much more convenient from the programmer's point of view, at least in the case of strings. Given that we decide to support BOTH start/count and start/end in a clean way, we have the naming problem to cope with. Yuck! One really wants to use "subsequence" or "subseq" to refer to a subsequence, but what to call the two different extraction primitives? Which case does SUBSEQ refer to, and what should the other case be called? The other name shouldn't be long (SUBSEQ-USING-START-END-INSTEAD-OF-START-COUNT, for example, is out). At least in the SUBSEQ case, I suggest the alternate names type-SUBSEQ => SUBtype (e.g., STRING-SUBSEQ becomes SUBSTRING) for the type-specific routines, as convenient and natural abbreviations. We also have the problem of names for shared versus nonshared subsequences to cope with... for example, a shared subvector cannot be implemented as a vector, because vectors, unlike strings, do not have headers; either you get a new, unshared vector, or you get some strange object which acts like a sequence but isn't a vector. So unshared vectors are natural. Whereas shared substrings are efficiently implemented, so one would like to use them. ALGOL68 uses the term "slice" to refer to a shared sub-array... so I'll suggest the following names, just to get people started flaming... I know the @'s are absurd (T philosophy: use as few special characters as possible), but here goes. (SLICE seq start count) - shared (SLICE@ seq start end) (SUBSEQ seq start count) - copied (SUBSEQ@ seq start end) Plus (type-SLICE seq ...), for important type-specific routines, (SUBtype seq ...), etc. (SUB@type? SUBtype@? yug.) The string routines of recent messages posted to this distribution list would be called STRING-SLICE@ and STRING-SLICE@-FROM-END. Personally, I prefer the start/count form; that's why I made the OTHER form have the ugly @'s in them. More naming problems: what to call (a) the routine corresponding to SUBBITV (BITV-SUBSEQ) which returns the result not as another sequence, but as an integer? And (b) the corresponding routines which extract not from a bit vector, but an integer? As far as I can tell, Common Lisp and Lisp Machine Lisp have nothing corresponding to (a) (the Lispm has no bit vectors per se, just ART-1B arrays... sigh...); corresponding to (b) are LDB and DPB, which in Maclisp have the alternate forms LOAD-BYTE and DEPOSIT-BYTE (the field is specified differently). NIL, I think, provides (a) and calls it NIBBLE, which seems a little bizarre to me. Interesting that Common Lisp uses start/count for LDB but start/end for SUBBITS. -------------------- --MORE-- Appendix. The concept of sequence and generic sequence operations for LISP originated (I think) with the NIL project; a good explanation and rationale for this mess is given in the draft Common Lisp manual, and a poor explanation is given in the new draft T manual. I should explain it here but don't have the energy at the moment. Apparently I've decided that generic sequence operations are a good idea for T. I don't want to go whole-hog with this idea like Common Lisp has, but I think it's a good overall guiding principle. More on this later if people are confused & have questions. (About my views on Common Lisp's sequences: I think I'm generally sympathetic. There's a lot of good stuff there. Common Lisp has even gone so far as to make things like LENGTH, APPEND, and REVERSE generic across sequence types, something I find myself wanting to do for T with increasing frequency; but my list-oriented constituency will scream gratuitous generality, especially before I've added some type analysis and declaration processing to the compiler. But Common Lisp provides so much, so many different kinds of iterators and such, that I feel certain it's left out a lot, and that some unifying concepts have eluded all who've thought about the problem. The implementation is going to be huge and complicated, and I try to avoid that kind of thing. I was the first person to try to implement NIL's generic sequence functions and felt sure there was something wrong then, and I still feel that way, even though I've been thinking about the problem for two and a half years...) Perhaps all these semantic & naming difficulties are evidence that the idea of sequence is either bogus or intractible; maybe strings and bit vectors really ARE different things, and we shouldn't be misled by their superficial similarity. I sincerely hope not... -------------------- Whew! Sorry about all this... had to get it off my chest...  Date: 7-May-82 8:25PM-EDT (Fri) From: Drew McDermott Subject: A modest proposal To: T-Discussion at YALE It seems to me that there is a perfectly consistent way to have 0-based indexing and negative indices. Simply allow the arguments to substring to be arbitrary integers: n denotes the (n mod length)th character (zero based). So the third character of "Feap" may be referred to as any one of ..., -6, -2, 2, 6, ... . Stripping the last character off may be done as (SUBSTRING "Feap" 0 -1). The problem with this is that there is no way to refer to the last character. (SUBSTRING "Feap" 3 4) is the empty string, since 4 is equivalent to 0. The solution is to number characters mod (+ length 1). The third character of "Feap" now has indices ..., -8, -3, 2, 7, ... . This amounts to pretending there's an extra character at the end of every string, numbered -1. Then (SUBSTRING ... 0 0) is empty (SUBSTRING ... 0 -1) is the whole string (SUBSTRING ... 0 -2) strips off one character etc. Notice that there is no way to get a substring containing the magic character, so it really isn't there. A committee should be appointed to study the advisability of having STRING-LENGTH return the number of characters in the string plus 1. I never use strings for anything, so you may be sure this proposal suffers from no untoward biases. -------  Date: 8-May-82 11:50AM-EDT (Sat) From: Chris Riesbeck Subject: substrings (sigh) To: T-Discussion at YALE Having flamed against "start,count", I must admit that -- given 0-basing -- "start,count" offers a solution I could live with. Using Rees' proposed nomenclature: (STRING-SLICE string m n) take n characters of (m to end) (STRING-SLICE string m -n) drop n characters from (m to end) To get all but the last character, (STRING-SLICE string 0 -1). Seems simple, concise, and consistent to me. SUBSTRING-FROM-END doesn't do the job of getting all but the last N characters than SUBSTRING. All it does is move the STRING-LENGTH calculation from the End-point to the Start-point. Conceptually, I want to say "Get a substring; start at the beginning, end at the second-last character." The choice of anchor-points is separate from the action of slicing. I think Drew's modest proposal would confuse the masses to please the few (e.g., me). So -- could people live with negative counts? -------  Date: Saturday, 8 May 1982 13:50-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: substrings (sigh) You're right - my proposed SUBSTRING-FROM-END was misconceived, and couldn't do what you wanted it to. Hmm. But I still oppose the idea of negative counts, for the reasons cited by Deutsch: loss of clarity, loss of error-checking, and loss of efficiency. So I still want to go with two different names. Actually, something involving the words TAKE and DROP might be nice... I'll think about it... until something good comes up, I'll go status quo, and omit from-end versions from the spec, leaving name & functionality up in the air...  Date: Saturday, 8 May 1982 22:10-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: New version of T compiler on -20. T cross-compiler version 16 on the research machine should be usable now. You need to have the following Tops-20 logical names defined: DEFINE TCOMP: DEFINE T-CODEGEN: DEFINE TAU: DEFINE T-KERNEL: where "machine" = VAX or 68000, depending on what target machine you're interested in generating code for.  Date: 12-May-82 8:21PM-EDT (Wed) From: Chris Riesbeck Subject: T compiler To: Rees at YALE, T-Discussion at YALE Right -- the FOR macro was used in GCON and hence couldn't be compiled by TC into anything intelligent. But now that you mention it, how do I tell TC about my macros? Also, can macros be compiled? -------  Date: Wednesday, 12 May 1982 22:05-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: T compiler Date: 12-May-82 8:21PM-EDT (Wed) From: Chris Riesbeck Re: T compiler ... But now that you mention it, how do I tell TC about my macros? Also, can macros be compiled? Funny you should ask. The interface is sort of minimal at the moment. Of course macros can be compiled; T touts compatibility between interpreted and compiled code, right? In fact, currently the ONLY semi-clean way you can get compiled file A to know about macros defined by file B is to compile file B first, and put the following as the very first form in file A: (HERALD A (ENV T "B")) The compiler, you will notice, puts out three "object" files for every source file compiled: LAP, SUPPORT, and NOISE. LAP, of course, is what you ship over, assemble, and fasload. The NOISE file has the compilation report - all the random statistics and environment info, to be read by humans (it's like a Maclisp UNFASL file). The SUPPORT file gets information about the things that are defined by the file, including macro definitions, integrable-procedure definitions, constant definitions, and number-of-args info. The compiler will make use of this information when it compiles some OTHER file, if that other file asks to get that information by including the support file name in the ENV clause of its HERALD. The HERALD form shown above says that the environment (ENV) which you want to be in effect for this file contains the standard T stuff (that's what the T is there for) together with stuff from the file B. HERALD is not a special form or macro; rather it is a peculiar thing seen by file transducers like the compiler and LOAD, which gives information about the nature and context of this file. It must be the first S-expression in the file. It is a bug that you need to compile your macro definitions before you can use them to compile another file. This will be remedied at some point. The CADR of the HERALD is identification which is passed on through to the fasl file; currently there aren't any programs which look at this. I suggest making this identification be the same as the filename (less directory and extension).  Date: 13-May-82 11:02PM-EDT (Thu) From: Chris Riesbeck Subject: SYMBOLCONC bug? To: Rees at YALE, T-Discussion at YALE The value of (SYMBOLCONC '\; 'FOO) prints as \\\FOO, while the value of '\;FOO prints as \;FOO. This seems to hold true for SYMBOLCONCing SET-SYNTAXed readmacro characters in general. -------  Date: Thursday, 13 May 1982 23:25-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: SYMBOLCONC bug? The value of (SYMBOLCONC '\; 'FOO) prints as \\\FOO, while the value of '\;FOO prints as \;FOO. ... I think you meant to say that it prints as \\\;FOO. Indeed there was a bug; SYMBOLCONC calls DISPLAY which didn't know how to handle symbols, so it was PRINTing them instead of DISPLAYing them, thus getting a \ in the symbol's pname. I fixed this in the source (PRINT.TAU) by adding a DISPLAY method for symbols; this will be reflected the next time Apollo T is brought up to date with the sources. In the meantime you might want to say (SYMBOLCONC ";" 'FOO), which works, and depending on the context might even be "stylistically better". Thanks for the bug report. This is the sort of thing I like: easily described and solved.  Date: 17-May-82 3:05PM-EDT (Mon) From: Chris Riesbeck Subject: walk/mapcan To: Kelsey at YALE Cc: Collins at YALE, Odonnell at YALE, Rees at YALE, T-Discussion at YALE O'Donnell pointed me to your definitions of MAPCAN and FOR on //alpha. Why do you return '() in MAPCAN? I know 'NIL isn't NIL, but isn't NIL or () what you want here? You also had a definition of WALK with the comment "A WALK that really works" -- what bug is (or was) there in the WALK in T? //beta/usr/riesbeck/utils.t contains the various TLisp utilities I've been bringing over, including LOOP, PRELIST/SUFLIST, MSG and so on. You might be interested and/or have coding or naming suggestions. Names right now are TLisp, but I don't care. TLISP_TO_T.LSP has functions to rename and reformat the more obvious functions, and warn about things like SET and DF. See TLISP_TO_T.DOC. Greg Collins was also bringing up some utilities for T on the VAX. Before more wheels are reinvented, we should centralize a list of what's been done and what's about to be done shortly. Is anyone else doing this kind of thing? -------  Date: Monday, 17 May 1982 15:34-EDT From: Norman Adams To: Riesbeck at YALE Cc: Collins at YALE, Kelsey at YALE, Odonnell at YALE, Rees at YALE, T-Discussion at YALE Subject: '() About '(): The T Project style sheet says (a) False and the null list are not assumed to be the same object (b) The variable NIL has false as its value; we don't depend on its having an external representation (c) Don't assume the empty list evaluates to itself Consequences: (a) Notate the empty list as '() in programs (b) Notate false as NIL The T style sheet is highly tuned dogma that we encourage you to use, though we plan no inquisition for the infidels. Also: RAK found a bug in WALK that we have fixed -- "the WALK that really works" was his patch.  Date: 17-May-82 3:57PM-EDT (Mon) From: John R. Ellis Subject: Initial Epidemic Strikes Yale To: Adams at YALE Cc: Riesbeck at YALE, Collins at YALE, Kelsey at YALE, Odonnell at YALE, Rees at YALE, T-Discussion at YALE In-Reply-To: Adams's message of Monday, 17 May 1982 15:34-EDT RAK found a bug in WALK that we have fixed -- "the WALK that really works" was his patch. Who is RAK? Can we please avoid the initials disease and use last names? -------  Date: 19-May-82 11:08AM-EDT (Wed) From: Chris Riesbeck Subject: cabbages and kings, etc To: T-Discussion at YALE Why is it (PUSH list item) instead of (PUSH item list) as in TLisp, Ellisp, and LispMachineLisp? I don't know what CommonLisp and MACLisp do. Isn't it better to agree with the syntax of CONS than with a PDP-10 machine instruction? It would be nice if there was something like ENFORCE (which is not documented in the first manual draft -- is it going to change?) which could pass a message to ERROR. As it stands, I don't want to use ENFORCE to protect code because all the user gets is (ENFORCE list? x) failed. If I could say something like (ENFORCE list? x "Non-list returned to MAPCAN") then I'd be more prone to insert lots of protective devices. The documentation should be a bit more specific about how CONJOIN and DISJOIN work, rather than leaving it up to the technical meaning of the term "predicate". That is, the manual should say that ((CONJOIN -preds-) arg) is like (TRUE? (*AND -(pred arg)-)), i.e., all the arguments are evaluated and only T or NIL is returned. Do they have to have these properties, by the way? Why is WITH-OUTPUT-TO-STRING so CONS-intensive? A dozen CONSes with no output at all (e.g., (WITH-OUTPUT-TO-STRING FOO)). I wanted to use it in a general any-type concatenator. Would it be possible in future releases to mark all to-be-implemented functions in some way so that instead of getting "NEGATE has no value" I get either "NEGATE has name xxx" or "NEGATE not yet implemented"? I ask this only so I can tell if something is coming, or has already arrived under another name. -------  Date: Wednesday, 19 May 1982 17:07-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: arg order for PUSH Arguments for (PUSH place item): - Consistency with other location modifiers: they all take the place-whose-value-is-being-hacked as their first argument. - Ellis, Pitman, Adams, and Rees like it, and as everyone knows, they're always right, esp. in concert. Arguments against (PUSH place item): - It's not status quo. Everyone (including Maclisp, Lispm, Common Lisp, UCI Lisp, ...) does it the other way. - It doesn't agree with the "natural" English rendering: "push item onto list". I give considerable weight to consistency arguments and not much to status quo. Naturalness is subjective and my conception will be different from other people's; anyhow, this is a programming language, not English with prepositions deleted. So we probably won't change it from its current definition: (PUSH place item). Unless there's a coup.  Mail-from: ARPANET site MIT-MC rcvd on Wed May 19 17:15:09 Date: 19 May 1982 17:09-EDT From: Kent M. Pitman To: Riesbeck at YALE cc: T-Discussion at YALE I can answer the question about PUSH. It's certainly not the case that we cared about being like a PDP-10 (I don't know where you got that idea from). Basically, it follows the same philosophy as SET, putting the location first and the expression second. The reason for this is that it has been repeatedly noticed over time (we were brought up on lisps that used the other arg order, too) that the location specification in PUSH (as for SET) is typically short while the expression to be pushed is often long. So you get things of the form: (PUSH (long (PUSH (long expression) or expression) var) var) (The latter drives me up a wall when people do it because it's a violation of grinding rules I'm comfortable with, but that's another issue.) ... Anyway, both are comparatively hard to parse visually by comparison to: (PUSH var (long or (PUSH var expression)) (long expression)) both of which are reasonably flavorful grindings and both of which are visually more tractable. I'll leave your other queries for Jonathan to answer. -kmp  Date: 19-May-82 9:34PM-EDT (Wed) From: John R. Ellis Subject: PUSH: More silly arguments To: T-Discussion at YALE For once I agree completely Kent Pitman. There is a very popular, very good convention that the "object" being operated is always the first argument of a function. Large numbers of people follow this convention, in many different programming languages (Lisps, Ada, Mesa, Clu, C, Fortran, ...). Some langauges such as Smalltalk enforce this convention. Even the TOPS-20 system calls tend to obey this convention (e.g. AC1 always gets the JFN, for file operations). In the literature on formal progamming methodology, stacks have been the traditional toy examples, and almost always the stack is the first operand of PUSH and POP. This convention stems from the so-called object-oriented methodology, which, as a general methodology, has proved extremely useful and powerful. The number of people who swear by the object-oriented approach is very large. For languages that don't provide explicit support for object-oriented programming (T and LM Lisp have only go halfway), the conventions are a real aid to clear programming. Arguing that the value being pushed on the stack should be the first operand because "that's how we say it in English" is very weak compared to the advantages of good programming conventions. -------  Date: 20 May 1982 0852-EDT From: Steven Shwartz Subject: PUSHing a human factors perspective To: Rees at YALE, T-Discussion at YALE I would like to cast my vote for (PUSH new-stuff list). This design decision has far-reaching consequences for T. By deciding for "consistency" and against "naturalness" you will please the purists but alienate the majority of potential users. I think it is a mistake to put the user-interface anywhere but first on the list of design decision criteria. -------  Date: 20-May-82 9:00AM-EDT (Thu) From: Chris Riesbeck Subject: re: push To: T-Discussion at YALE My last attempt at pouring oil on troubled waters seems to have disappeared -- at least I didn't see it. If you experience deja vu (more so than this argument should already engender), please accept my apologies. The consistency argument (change changed-thing item) is fine by me, but it doesn't seem reasonable to warp PUSH to fit it, when both English AND Lisp conventions say otherwise. Therefore, don't use PUSH. Call it something else. There's no benefit in reusing an old name if the old name is going to confuse people -- AND IT WILL!!! Also, complete consistency is not an achievable goal in these matters. For example, what is the consistent order of arguments for the "add an item to the end of a list" function? (CONS-END item list) to be consistent with CONS, or (APPEND1 list item) to be consistent with APPEND? Depending on the name you choose, you get a different answer. -------  Date: 20-May-82 9:11AM-EDT (Thu) From: Josh Fisher Subject: PUSH To: T-Discussion at YALE The whole point of using the name PUSH is to suggest the English meaning of the word. How can it be ignored when people have such a strong intuition about it? We push things onto things. I don't buy Ellis' arguments about sacrificing intuition for 'good' (read corresponds to object oriented point of view) programming conventions. When the intuition is weak, then naturally the convention makes sense. But here, the intuition is very strong. Almost every programmer is going to get it wrong most of the time, especially for the first 1000 lines, and it's going to be a constant irritant. Taken by itself, it's not so bad. Taken as a philosophy, it's going to make for an aggravating language. -------  Date: 20-May-82 9:47AM-EDT (Thu) From: John Ruttenberg Subject: PUSH To: T-Discussion at YALE For what it's worth, it took me quite a long time to get the current argument order of push right. All the people who have spoken up on the side of the old (push new-thing list) order have "intuitions" that have been shaped by long use of current lisps. Ask yourselves, "Would they be as strong if I were a brand new lisper?" Brand new lispers will choose consitency since it means there is less for them to learn. -------  Date: 20-May-82 10:04AM-EDT (Thu) From: Chris Riesbeck Subject: Re: PUSH To: T-Discussion at YALE For what it's worth, it took me quite a long time to get the current argument order of push right. All the people who have spoken up on the side of the old (push new-thing list) order have "intuitions" that have been shaped by long use of current lisps. Ask yourselves, "Would they be as strong if I were a brand new lisper?" Brand new lispers will choose consitency since it means there is less for them to learn. 1) It's impossible for anyone to tell what they would have done if they didn't already know something -- I THINK I would still take English order (PUSH X against Y), but only a real experiment would tell. 2) There are unlikely to be any brand new Lispers starting on T for some time - it'll be too shakey a system for that 3) When they do, brand new Lispers won't know what counts as consistent - that comes when one has working familiarity with a large number of functions - I've taught several courses of Lisp for the first time (no previous programming) and no matter how many times you tell them the most consistent rule Lisp has, namely (A B C ...) means A is a function applied to the arguments B, C ..., they have to learn it for themselves 4) I still say, use another name and make everyone minimally happy. -------  Date: 20-May-82 11:42AM-EDT (Thu) From: David Miller Subject: PUSH-ONTO vs PUSH To: T-Discussion at YALE I agree with Chris. If you are going to reverse the order of the arguments for PUSH then call it something else --perhaps even something that makes intuitional sense as well. Perhaps the best name or at least the most accurate would be (CONS-ONTO! list item) this lets its arguments follow the order conventions, is intuitive, tells what the actual process is, and uses the "!" convention, which is such a clever idea anyway. --Dave -------  Date: 20-May-82 11:42AM-EDT (Thu) From: Chris Riesbeck Subject: yet another blow for purity To: T-Discussion at YALE Cripes! (COND ( ...) ) => *NO-MORE-COND-CLAUSES* I know that you should always have an ELSE clause, you know that I should always have an ELSE clause, but tell that to years of old code by me and many others, not to mention macro-expansions. I'm sorry, but it's hot and muggy and I'm trying to get something real up and running on the Apollo to see if anything real will really fly, and I have better things to do with my time than fight a Lisp based on the "thou shalt not" principle. Sorry for the tone, but my back is getting very loaded down with straws. -------  Date: 20-May-82 3:16PM-EDT (Thu) From: Chris Riesbeck Subject: T compiler To: T-Discussion at YALE How do I tell TC about readmacros? In particular, I have a comment readmacro in COMMENT.T that I compiled and heralded in UTILS.T, but that didn't work, even though TC did find COMMENT.6SUPPORT (which doesn't seem to have anything interesting in it). Also, can I say (I hope, I hope) TC file1,file2, ... and not have to spend 5 to 10 minutes of each compile loading in support files. -------  Date: 20-May-82 3:17PM-EDT (Thu) From: John R. Ellis Subject: Re: PUSHing a human factors perspective To: Shwartz at YALE, Riesbeck at YALE, Fisher at YALE, Ruttenberg at YALE, Miller at YALE Cc: Rees at YALE, T-Discussion at YALE, Nicolau at YALE, Vanleunen at YALE In-Reply-To: Shwartz's message of 20 May 1982 0852-EDT Rees can decide to do whatever he wants about PUSH. But there is a more serious issue here that will continue to crop up again and again, not just in T, but in programming in general. This is a long message, so the weak-minded will want to type ^O and flush it. It is requiried reading for Fisher and Nicolau. From: Steven Shwartz Subject: PUSHing a human factors perspective ... By deciding for "consistency" and against "naturalness" you will please the purists but alienate the majority of potential users. I think it is a mistake to put the user-interface anywhere but first on the list of design decision criteria. ------- From: Chris Riesbeck ...There's no benefit in reusing an old name if the old name is going to confuse people -- AND IT WILL!!! ------- From: Josh Fisher The whole point of using the name PUSH is to suggest the English meaning of the word. How can it be ignored when people have such a strong intuition about it? ...Almost every programmer is going to get it wrong most of the time, especially for the first 1000 lines, and it's going to be a constant irritant. ------- Has it ever occurred to anyone that "methodology", "consistency" and "convention" have as much to do with "human factors" or "user interfaces" as "naturalness"? My endearment to one particular methodology has nothing to do with "purity" or "idealogy". The very purpose of programming methodology is to find ways of programming that reduce the human cost. Current programming languages are NOT natural languages, they are formal engineering notation systems with many complicated rules. We all want to make those rules as simple, as easy to learn and remember as possible. Other more mature disciplines have evolved highly formal notation systems that are divorced from natural, casual language: music, drafting, mathematics, business, etc. Why shouldn't programming? (If I could talk to the computer in English, great, but that's not what we're discussing here). But those notations still use English words, in often "unnatural" ways. "Naturlness" is only one small criterion to be used in desiging a programming notation (or any notation, for that matter). Consistency and convention are generally more important, because they allow (and encourage) programmers to treat the programming language as a formal model, not as a bag of special cases that must all be memorized. The assumption is that, though possibly more painful to learn at first, formal models and conventions are cost effective in the long run, because they can be confidently applied to new situations, whereas a body of special cases cannot so easily be applied or communicated. In a large program, there are many hundreds of different "objects" or constructs, each with its own set of operations. If no conventions were obeyed and the operations used any naming and argument conventions that seemed "natural" at the instant the programmer implemented them, you would end up with a big mess that only the original programmer could understand. But if you follow consistent conventions, the OTHER programmers reading the code don't have to understand and remember one person's quirky understanding of "naturalness"; they only have to learn the conventions and formal models. Systems programmers routinely look at and modify code written by dozens of other people. Communication of intent to other programmers is at least as important as communication to the machine. The hardest programs to read and modify are those that don't follow any quickly discernable conventions in program surface structure (argument order, naming, pretty printing, etc.). A formal convention provides a uniform surface structure, allowing the programmer to concentrate on more important issues. Picking names for operations is always a tricky business. We want the names to do a lot of the mental drudge work for us, helping us to remember the semantics of the thing the name represents. Unfortunately, the ambiguity and extreme richness of English confuses the issue, as we've all seen with the PUSH example. Anyone can apply the same arguments about the naturalness of PUSH to many other functions with English names. For example, try try to explain (APPEND X Y). Using the naturalness approach, I sure want to read that as "APPEND X to Y", which actually implies a destructive operation!. But we all know that it should be read as "APPEND Y to X, yielding a new list, without destroying X or Y. By using a consistent argument and naming convention, we can eliminate much of the ambiguity implied by the names of operations. The programmer KNOWS for certain that the object being manipulated or changed comes first in the argument list. The operation name describes ONLY the operation being done, NOT the order of arguments. When I first started using Lisp (I came from a PL/I background), one of its most enjoyable aspects was the rich library of powerful operations. The most irritating thing was the total chaos in naming and argument conventions. I still can't remember them; a reference manual by my side is a must. Rees and Adams and Pitman and the other "purists" have done an admirable job in making T less of a reference manual language, and more of a notation that can be written without resort to page flipping. I can't think of any more important "human factors" issues than these. -------  Date: 20-May-82 3:31PM-EDT (Thu) From: Gregg Collins Subject: PUSH To: T-Discussion at YALE It seems to me that a there is a "consistancy" to be maintained in the design of list -building and -modifying functions which is much more salient to the programmer than which argument is being operated on. That is that nearly in nearly all such functions (CONS, APPEND, NCONC, etc.) the order of the arguments in the function call reflects the order in which their contents will appear in the constructed list. Because of this I'm not happy about the proposed design of PUSH and still wouldn't be if the name were changed. -------  Date: 20-May-82 4:04PM-EDT (Thu) From: Margot Flowers Subject: Re: PUSH / human factors / consistency principles To: T-Discussion at YALE In-Reply-To: Your message of 20-May-82 3:17PM-EDT (Thu) One problem with striving for consistency is that there are many dimensions to which consistency can apply. For example, I happen to be perhaps more visually- or structurally-minded than most, so I like the argument order of things that build structures to reflect something about resulting order of components of that structure. I think this is especially relevant to a language like LISP. For example UCI LISP reversed earlier LISP's argument ordering for the PUTPROP functions, to be (PUT atom val prop-name). However, because PLISTS internally are a list consisting of property names *followed by* values, I find UCI LISP's argument order confusing and counterintuitive. As a result I program using only my versions of PUTPROP that correct this flaw. CONS and APPEND reflect this principle too. Thus, when I want to push an item on a list, saying: (PUSH ITEM (ITEM1 ITEM2 ITEM3 ...)) reflects the resulting structure better than saying: (PUSH (ITEM1 ITEM2 ITEM3 ...) ITEM) which, according to my criteria, is ass backwards. That is basically Gregg's point too. I find this a much stronger principle than the object-oriented principle that, to the best of my introspection, has never participated in my use of LISP, and which I don't find terribly relevant (maybe because I try to avoid side-effect programming as much as possible). Another /minor\ rule of thumb I use in determining argument order is to try to put the "simpler" or "smaller" arguments first. This yeilds, I believe, slightly clearer and more readable code. For example according to this, the (PUTPROP atom property-name value) argument order is preferable, since the property-name is practically always an atom, but the value may be a complicated expression. Having the item before the list with PUSH would usually produce a cleaner expression also. -------  Date: 20-May-82 4:44PM-EDT (Thu) From: John R. Ellis Subject: Re: PUSH / human factors / consistency principles To: Flowers at YALE Cc: T-Discussion at YALE In-Reply-To: Flowers's message of 20-May-82 4:04PM-EDT (Thu) The arguments about visual order reflecting internal lisp structure are stronger arguments (as compared to English-usage arguments). ...I find this a much stronger principle than the object-oriented principle that, to the best of my introspection, has never participated in my use of LISP, and which I don't find terribly relevant (maybe because I try to avoid side-effect programming as much as possible). The object methodology and side-effect programming are orthogonal concepts. Traditonal Lisps and Lisp programs, like other programming languages, generally don't use any kind of object-methodology at all, and they suffer because of it. This contributes to their baroqueness. T is not a traditional Lisp by any of the imagination. Another /minor\ rule of thumb I use in determining argument order is to try to put the "simpler" or "smaller" arguments first. This was Kent Pitman's argument for why it should be (PUSH STACK VALUE). -------  Mail-from: ARPANET site MIT-MC rcvd on Thu May 20 17:27:01 Date: 20 May 1982 17:26-EDT From: Kent M. Pitman To: Ellis at YALE cc: Flowers at YALE, T-Discussion at YALE Sorry, John, I think you're wrong. Any argument based on reflecting the internal representation of anything is suspect. Abstractions are abstractions. No one should ever depend on the storage format of a property list. There's no reason you should even assume it's really stored as a list. Certainly in T we thought about making it be a hash table internally and would like to leave open the possibility of doing that later. Good tools should be available for getting efficient access to all the plist's contents, but there's no reason for you (the user) to know how those tools work. Anyway, PUSH/POP is a weaker case of the same -- the only thing you should really have to know about PUSH is that (PUSH loc x) followed by (POP loc) gives you back x and returns the contents of loc to the state it had before the PUSH. Talking about internals just makes your code awfully dependent on a lot of details that it ought never deal with because it ties you to a particular implementation. I think Margot's idea of worrying about making code reflect internal detail is a bad one. -kmp  Date: 20-May-82 5:53PM-EDT (Thu) From: John R. Ellis Subject: Re: To: Kmp at MIT-MC Cc: Ellis at YALE, Flowers at YALE, T-Discussion at YALE In-Reply-To: Pitman's message of 20 May 1982 17:26-EDT Any argument based on reflecting the internal representation of anything is suspect. Abstractions are abstractions. Kent missed the main point of Greg's and Margot's arguments. I wasn't talking about "internal representation", and Margot wasn't either as regards PUSH/POP. Ignoring what she said about property lists (I agree with Kent, hide that representation), her general point is still good-- it is nice to have a kind of visual concordance between list structure AS IT IS VISUALIZED (prints out) and the functions that manipulate list structure. That, after all, is one of the main virtues of backquote; the lists it constructs look like the code you write. Margot and Greg argue that all the other list functions order their arguments according to how the resulting list structure prints out. E.g. (LIST 'A 'B 'C) => (A B C), not (C B A), (CONS 'A '(B C) ) => (A B C), (APPEND '(A B) '(C D) ) => (A B C D). Since PUSH puts a value at the front of a list, why shouldn't the value be the first argument? For consistency (according to them) the syntax should be (PUSH value stack). I think this is a valid, strong argument. I don't think it outweighs the other arguments though. -------  Date: 20 May 1982 1828-EDT From: Margot Flowers to: Ellis at YALE, KMP at MIT-MC cc: T-Discussion at YALE subject: Re: PUSH structure versus visualization In-Reply-To: Ellis's message of 20-May-82 5:53PM-EDT (Thu) it is nice to have a kind of visual concordance between list structure AS IT IS VISUALIZED (prints out) and the functions that manipulate list structure. That, after all, is one of the main virtues of backquote; the lists it constructs look like the code you write. Actually, I should have emphsized structure over visual order. That is, the structure of the function's s-expression should (in my mind) reflect the structure of what is being constructed. Necessarily this shows up in the visual representation of that s-expression. ----- In-Reply-To: Pitman's message of 20-May-82 4:26PM-EDT (Thu) ... Any argument based on reflecting the internal representation of anything is suspect. ... I think Margot's idea of worrying about making code reflect internal detail is a bad one. -kmp I agree with most of his argument except for the conclusions. Having code depend upon the internal format (which I do not advocate) is not the same as using your MODEL of that structure to help remember how to use the functions which are applicable to that structure. The internals are unimportant as long as it behaves according to the model. Like it or not, people do use models to keep straight otherwise disconnected rules, and when models are not provided, that people construct them. For this reason, it is unrealistic to say that: the only thing you should really have to know about PUSH is that (PUSH loc x) followed by (POP loc) gives you back x and returns the contents of loc to the state it had before the PUSH. If a model is suggested, and the available functions are not consistent with that model, then programming errors will result. As long as you talk about PUSH and POP I'm going to think of stacks, and of lifo lists. Even if the PLIST internals are different, I'm going to think of a list of associated property-names and values. Thus, a design as consistent as possible with the models people use makes a language easier to use. (But my code will use PUT and GET etc. rather than CAR and CDR to access plists.) Besides, when I constuct my own structures, I cannot be ignorant of their structural properties even though I don't write my code to depend upon them. ----- As far as English usage goes, if a function name has a clear English meaning, then that should be exploited in the language design, it is either that or confusion. If the language design differs from English usage, then don't use English.  Date: Thursday, 20 May 1982 18:16-EDT From: Norman Adams To: T-Discussion at YALE Subject: Thou shalt not with MY lisp implementation [ Jonathan says he will send his response to the PUSH controversey when he gets the Lisp Conference paper under control ] T imposes restrictions on the programmer that traditional lisps do not. These restrictions are not engineered specifically to annoy established Lisp programmers; rather, the restrictions are intended to encourage a style of programming where the resultant programs do not contain hidden dependencies and assumptions. T is not the "New Implementation of Lisp." In designing T, we are faced with deciding between restrictions that are useful, and ones that are not. We are guided by people we know that have lived with the kind of restrictions that T imposes; and our own experiences. For example, from our experience we observe that consistency is rarely a bad thing. Remember, we have to use this language too. We have written more than 20000 lines of running T code; we have an interest in the language being usable and maintainable.  Mail-from: ARPANET site UDEL-RELAY rcvd on Fri May 21 02:32:52 Date: 20 May 82 22:57:32-PST (Thu) From: Jim Meehan To: t-discussion at Yale cc: meehan.Uci at UDel-Relay Subject: My $.02 on PUSH Via: UCI; 21 May 82 2:16-EDT I've just been assaulted by 16 count 'em 16 messages on PUSH, dutifully wrapped in headers, mailed to Delaware, and forwarded to California. (DoD is paying for this?) A bit of history. Riesbeck insists that I am responsible for having reversed the order of parameters to PUSH in UCI LISP. He claims that Rutgers LISP (one of the LISPs merged into UCI LISP) did it the other way around. I deny all this, but his conviction is stronger than mine, so maybe he's right. "Mea culpa" to those of you who want the stack to come last. I most certainly did NOT change the order of parameters to PUTPROP (Margot, where DID you get that idea?), as you can check by looking at any vintage Stanford LISP 1.6 Manual. On the issue itself, I have only a few comments. First of all, most of the flaming is silly. There are good arguments for both versions of PUSH; it's not some obvious, gross error. Moreover, lots of things are like that. I.e., idioms exist in programming languages as well as natural languages. There's a limit to how clean you make any language. Beyond a certain point, you stop shouting, learn the convention, and go back to work. Nobody ever said that programming was supposed to be intuitively obvious. Some things (organic chemistry, twelve-tone rows, and PUTPROP) just take time to learn. So what? One of the joys of LISP, in my view, is that you can extend it to suit your own tastes. You don't like PUSH? Fine -- define your own function (the Burger King approach). Sure, (PUSH X Y) may be ambiguous, but no respectable programmer would misunderstand (PUSH (CONS X Y) Z) or (PUSH X (CONS Y Z)). Better yet: You want English? You got it. In UCI LISP at least, PUSH is a macro, and it's downright trivial to redefine it to include a "guide word": (PUSH A ONTO B). I take programming-aesthetic arguments with a grain of salt, but what does irritate me are arbitrary changes that INTRODUCE incompatibilites or inconsistencies. I am one of the greatest fans of the AIP book, and I've probably taught it to as many students as anyone else has, but for the life of me, I don't know why they made PUSH different from UCI LISP, which they use as the dialect for the rest of the book. Likewise, I think all the neat stuff in TLISP was great, but restricting channel names to be legal JFNs was a piece of crockery that eliminated, as a side-effect, one of the elegant things about old INPUT, namely, that it took a STREAM of files as its parameter; pretty neat for 1960's software. As far as T is concerned, I'm resolved to the fact that I'm going to have to re-learn a lot of nitty-gritty information: NTH returns elements now instead of tails, MAP is actually MAPCAR, etc. Undoubtedly, I'll wind up writing a UCI LISP - to - T translator. As long as there's SOME good reason for the differences, I don't mind so much, given that it's a new language anyway. You think we got problems? The physicists have just learned that the sun isn't spherical, and Einstein's theories assumed it was. Back to the drawing board, in spades! At least they don't send messages to each other claiming the sun SHOULD be round.  Date: Monday, 24 May 1982 19:40-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: [Riesbeck: arg order for PUSH] Date: 19-May-82 6:56PM-EDT (Wed) From: Chris Riesbeck To: Rees Re: arg order for PUSH Granting both real arguments for (PUSH place item) [consistency with other location modifiers and better prettyprinting potential], why call the damn thing PUSH? Why pick a name that has contrary tendencies from BOTH English and Lisp? How about SUCK? Or if that's sounds negative, IMPRESS or some long name that seems so popular in T such as SET-THE-NEW-FIRST-ELEMENT?  Date: 27-May-82 10:41PM-EDT (Thu) From: Nathaniel Mishkin Subject: Gross You Out To: T-Discussion at YALE THe following is a feature which let's you load files from the -20 into a T running on the VAX: (load "/ed/+foo.t") The "+" must be there. Substitute "ai" for "ed" if you want the research machine. This isn't really tested out to much; it may have bugs like losing characters at the end of the file. Bob Nix is playing with it. -- Nat -------  Date: 27-May-82 12:53AM-EDT (Thu) From: John R. Ellis Subject: T-BUGS To: T-Discussion at YALE Just a reminder: Local users can read T-BUGS like a bulletin board: NEWS -CB T-BUGS (or MSG). -------  Date: 27-May-82 2:22PM-EDT (Thu) From: Michael Fischer Subject: T-DISCUSSION To: Rees at YALE Cc: T-Discussion at YALE Why not keep life simple and put T-DISCUSSION into like all the other bulletin boards? --Mike -------  Date: Thursday, 27 May 1982 00:31-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: Mailing Lists New distribution list: T-BUGS. From now on, please send T and T compiler bug reports to T-BUGS instead of T-DISCUSSION. The more interesting bug FIXES will continue to be posted on T-Discussion for now. Maybe there should be a T-Users, distinct from T-Discussion? Please do not add yourself to the T-BUGS list. The file [YALE-RES]T-BUGS.TXT holds a transcript of messages sent to T-BUGS; look there if you're interested. The transcript for T-Discussion now resides in the following places: [YALE-RES]T-DISCUSSION.TXT (note change: not any more) [YALE-CS]T-DISCUSSION.TXT (may also move to someday) [MIT-MC] LSPMAI; T MAIL  Date: Thursday, 27 May 1982 00:48-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: Using the Compiler Some of you have complained about the amount of time that TC takes to start itself up. This could be reduced if we were ready to devote another few hundred disk pages to pre-dumped target-machine-specific versions; I'll look into that. In the meantime, note that running TC with no arguments on the command line, OR continuing the TC after it quits after doing a compilation, will put you in a Maclisp read-eval-print loop; say (COMFILE "FILENAME.TAU") or whatever, to compile a file. You incur the startup overhead only when you start the TC process; you can leave it around all day (unless you want to help keep swap space available so other people can get work done...). The compiler is fairly robust in the sense that you may use it to compile many files without restarting it. (This is in contrast with the Maclisp compiler, which becomes "stale".) If there are errors and you want to abort, type control-G and say COMFILE again. (You can even compile recursively!) ADVANCED FEATURES: Only the most devoted T fans need read further: If you want to see gobs of compilation trace information (like what transformations the optimizer is performing), do (SETQ *TESTING* T) before compiling something, and type a ? when it asks you a question. You can compile procedures without putting them in files by saying (CL (LAMBDA (...) ...)), or by saying (DEFINE (FOO ...) ...) and (CL FOO).  Date: 1-Jun-82 11:12PM-EDT (Tue) From: John R. Ellis Subject: Re: T-Tools To: Nix at YALE Cc: T-Discussion at YALE In-Reply-To: Nix's message of 1-Jun-82 10:45PM-EDT (Tue) Bob's suggestions were all good (except one). Maybe he is volunteering to become the T Big G? - A strong effort should be made to make each package stand on its own. Ideally, a particular package should not require the presence of any function outside of the T core to run. Note that this is not a restriction on the macros it uses, just the object code created from it. What's the point of packages if you can't use them? If the packages are good, people will want to use them for building other packages. E.g. a database package might want to invoke the process manipulation package; I'm sure other people can come up with better examples. The only reason for making a package "stand alone" is because there are few good source code and module control tools of the sort found for Mesa or Unix. But even a primitive system (just slightly more sophisticated than ELLISP BUILD and REQUIRE) would be adequate for the initial T community. For example, it would be sufficient (and easy) to put REQUIREs of dependent modules at the top of each module. For the most useful packages, you would quickly discover obvious holes where people left out REQUIREs. Just think if the BLISS runtime library or CEDAR didn't have internal dependencies? -------  Date: 2-Jun-82 9:11AM-EDT (Wed) From: Nathaniel Mishkin Subject: Re: T-Tools To: Nix at YALE Cc: T-Discussion at YALE In-Reply-To: Nix's message of 1-Jun-82 10:45PM-EDT (Tue) For those of you unaware of it, there is a CHKIN/CHKOUT "subsystem" called T-UTILS (or something like it) on the Apollos. This is where Chris' stuff is and all future stuff should go. It gets released into the directory /tools/t/utils. Since there is going to be overlap between the Apollo and Unix T utilities, we'll need to make some system for keeping the two versions in synch. This will be easier when we have Chaosnet to the Apollos working (within a week or so hopefully). For those of you unfamiliar with the CHK stuff: it is a scheme for orderly modification and distribution of programs, documentation, etc. See /tools/help/chk.hlp on any node. -- Nat -------  Date: 1-Jun-82 10:45PM-EDT (Tue) From: Robert Nix Subject: T-Tools To: T-Discussion at YALE I found this in the T-Discussion archives: Date: 17-May-82 3:05PM-EDT (Mon) From: Chris Riesbeck Subject: walk/mapcan To: Kelsey Cc: Collins, Odonnell, Rees, T-Discussion O'Donnell pointed me to your definitions of MAPCAN and FOR on //alpha. ... //beta/usr/riesbeck/utils.t contains the various TLisp utilities I've been bringing over, including LOOP, PRELIST/SUFLIST, MSG and so on. You might be interested and/or have coding or naming suggestions. Names right now are TLisp, but I don't care. TLISP_TO_T.LSP has functions to rename and reformat the more obvious functions, and warn about things like SET and DF. See TLISP_TO_T.DOC. Greg Collins was also bringing up some utilities for T on the VAX. Before more wheels are reinvented, we should centralize a list of what's been done and what's about to be done shortly. Is anyone else doing this kind of thing? ----------- Is anyone else doing this kind of thing? Yes, they are!!! Unfortunately, I didn't know about Chris's LOOP macro until I had just about finished mine-- let this be a lesson to those who skim and delete their mail when they return from a trip. We should start a mailing list, T-Tools, for announcements of packages of general interest to T users. The sources, documentation, and LAP files for these packages should be maintained and documented in a central directory, say on one of the -20s for now. Shadow copies of all of these files, plus object files, should be automatically distributed to several standard locations on the Apollos and VAX(s). When T moves off the -20, T-Tools should still be centrally maintained on some Apollo or VAX. Without centralization and semi-automatic administration, the only effective contributors to T will be Rees and Adams. Some sample packages: - Common macros: FOR, LOOP, etc. - Data structure hacks: sets, priority queues, hash tables, etc. - Data structure browsers. - Readers. - Process manipulation for the Apollos and VAXs. - Display utilities for the Apollos and VAXs. - System call utilities (data structure definitions, etc.) - FFT, Matrix multiply, ... And we must, of course, have Programming Standards: - Every package must be completely documented. This documentation must be in Scribe-able form, using standard T Manual conventions. - Names must obey T conventions. - All "public" functions must do dynamic type and bounds checking on entry. - A strong effort should be made to make each package stand on its own. Ideally, a particular package should not require the presence of any function outside of the T core to run. Note that this is not a restriction on the macros it uses, just the object code created from it. - Every package must be compiled, and be as efficient in time and storage as possible. Every macro must generate efficiently compilable code. ? Every package should obey the T object-oriented programming standards. -- Bob Nix -------  Date: 8-Jun-82 10:38AM-EDT (Tue) From: Chris Riesbeck Subject: What I've put in /Tools/T/UTILS To: T-Discussion at YALE Here are the TLisp utility functions I've generated so far for T on the Apollo. None have been compiled yet, due to problems with readmacros and macro subfunctions, but I'll get around to it Real Soon Now. None of this satisifies reasonable documentation standards, but Meehan's New UCI Lisp Manual and TLISP:TLISP.DOC describe almost everything. Functions names are taken from TLisp, except when this led to conflict with T. Suggestions for new names are welcome, but less than 20 characters and 4 non-alphabetics please! In UTILS.T: ADD1 and SUB1 -- until they appear in T for real APPEND1 -- (APPEND1 list exp) = (APPEND list (LIST exp)) APPEND1! -- APPEND1! list exp) = (NCONC list (LIST exp)) ATCAT -- (ATCAT -exps-) returns an atom formed by concatenating the print representations of all the -exps-. CONSP -- (CONSP exp) = (AND (LIST? exp) exp) := -- a macro for assignment like SET but with user hooks for new data structures; from Artificial Intelligence Programming CONS! -- (CONS! exp list) = (PUSH list exp) LDIFF -- (LDIFF list1 list2) returns the portion of list1 before list2, if list2 is a tail of list1 LOOP -- (LOOP (INITIAL -(var val inc)-) (BEFORE -exps-) (WHILE exp) (DO -exps-) (NEXT -(var val)-) (UNTIL exp) (AFTER -exps-) (RESULT exp) We really need to resolve, at least with new names, the clash between this LOOP and Nix's in NEWLOOP. The syntax of of INITIAL and NEXT has changed, and the semantics of INITIAL is now like MacLisp's DO. TLISP_TO_T is aware of this and tries to do the safe thing when translating LOOPs. PRELIST -- (PRELIST list n) returns first n elements of list. SUFLIST -- (SUFLIST list n) drops the first n elements from list. MSG -- (MSG -cmds-) is a general print utility, an alternative to FORMAT In MORE_MAPS.T: MAPCAN -- (MAPCAN fn -lists-) applies fn in parallel to elements of the lists, splices the answers together with NCONC. SUBSET -- (SUBSET fn -lists-) applies fn in parallel to elements of the lists, returns all elements of the first list for which fn returns true. In FOR.T: FOR -- (FOR -(var IN list)- (WHEN -exps-) (DO | FILTER | SAVE | SPLICE | UNTIL | WHILE -exps-) This is the FOR used in CS 472. It expands into various mapping functions, including MAPCAN and SUBSET. Multiples expressions are implicitly BLOCKed. -------  Date: 8-Jun-82 11:08AM-EDT (Tue) From: Chris Riesbeck Subject: read-line To: T-Discussion at YALE What is READ-LINE supposed to do? I tried (READ-LINE si) but got an error message, saying that the standard-input didn't support READ-LINE. Is this a temporary difficulty? Both the old Lisp Machine manual that I have and the pre-release T manual say the same thing: "Reads a line of input from [the input stream]." What does this mean? Is a string returned? A list of expressions? What if the line has an incomplete expression? TLisp has LINEREAD/READL which reads a line, returning it as a list. If some expression takes more than one line or a line terminates in a comma, space or tab, then READL continues reading until an expression ends at the end of a line. Is the same as READ-LINE? Also, TLisp's LINEREAD takes an optional flag argument which, if NIL, means at least one expression is read. If this flag is true, then zero expressions are read, if the line is empty. This latter mode usually requires clearing the input buffer of any leftover carriage return. Does READ-LINE have such a feature? -------  Date: Tuesday, 8 June 1982 11:24-EDT From: Norman Adams To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: read-line READ-LINE reads a "line" and returns it as a string, where "line" corresponds what people think of as a line in the printed representation of a file. The READ-LINE operation will soon be supported the standard IO streams, in the Apollo implementation. I think the same is true for the VAX. Along with this I expect to have buffer IO streams, which should make a substantial improvement in the reader's performance. You can expect a release by the end of the week.  Date: Friday, 11 June 1982 12:15-EDT From: Norman Adams To: T-Discussion at YALE Subject: New Apollo T Release The is a new release of T for the Apollo (version 1.67) that you can get using CHKUPD. Features include: (some of these may have been reported previously, please forgive redundancy) - INIT.T is loaded from the working directory. - CAR/CDR chains up to 4 long (e.g. CADDAR) are provided, and they are settable (i.e. they work with SET, SWAP, PUSH, INCREMENT, etc.). - LOAD has been fixed so that it doesn't crash T if you give it the name of a non-existent file. It still has the bug that the file won't get closed if the LOAD is thrown out of (e.g. with RESET); this will be fixed within a month. Use the (CLOSE *LOAD-CHANNEL*) kludge for now. - Dynamic bindings are now restored across throws (e.g. when a RESET is done). E.g. (BIND ((X 'WIN)) (LIST (CATCH FOO (BIND ((X 'LOSE)) (FOO 'WE))) X)) formerly returned (WE LOSE) [wrong], now returns (WE WIN) [right]. - (FILE-EXISTS? string) now exists to probe existence of files. - (MAYBE-OPEN string modes) is like OPEN but returns () if the file - Typing ^Z (that is, end-of-file) at break level does a (RESET). - Bit vectors (BITV's) are provisionally implemented so that Nat can do stuff with CALL-XENOID. Send mail for details. - If you want () to not be self-evaluating, do (SET *NULL-SELF-EVALUATES?* NIL). - There is a simple DEBUG. It's practically useless right now; it lets hard-core hackers inspect stack frames (the X command), for what that's worth. Better debugging tools are in the works. Incompatible changes: - Objects such as vectors, procedures, and xenoids, are no longer self evaluating. Only numbers, strings, characters, and () are. - Some renamings: (note that channels are an internal hack only) STRING->STREAM => STRING->INPUT-STREAM CHANNEL-MAKE-INPUT-STREAM => CHANNEL->INPUT-STREAM CHANNEL-MAKE-OUTPUT-STREAM => CHANNEL->OUTPUT-STREAM STREAM-CHANNEL => STREAM->CHANNEL Some of the old names are still provided for compatibility; in the future we'll be more careful about doing this, and uses of the old names will produce annoying little remarks telling you to change your code. We have just started to get organized about keeping histories for our sources. So there may be other changes not noted here because we forgot we did them. If you want to keep abreast of all the weird things we work on, check out the files [RES]T-HISTORY.TXT and TCOMP-HISTORY.TXT.  Date: Thursday, 10 June 1982 18:23-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: Coping with TC Date: 8-Jun-82 6:17PM-EDT (Tue) From: Chris Riesbeck To: T-Bugs Re: bug in TC? The file UTILS.T appears to compile file, but the file PRELIST.T which uses the LOOP macro defined in UTILS blows up immediately with a LABELS undefined function object message. UTILS+PRELIST works fine interpreted on the Apollo. I don't know if the compiled UTILS works correctly to support PRELIST. If you get LABELS UNDEFINED FUNCTION OBJECT it's probably because some macro expander requires more than just those routines which are in Maclisp and in the compiler's "T compatibility mode" to run, e.g. LABELS. TCOMP in Maclisp has no T interpreter; macro expanders are run directly in Maclisp, and usually work only if they're pretty carefully written. This problem should go away when the compiler runs in T, which should be by July 1. If you think there are some things I've left out of the (undocumented) compatibility mode which can be trivially added, let me know. If you think you can write your code so it'll run in Maclisp but not compatibly with T, then make use of the following kludge/feature: put the macro definitions you need in some file FOO.6SUPPORT and put as the first form of your file (HERALD PRELIST (ENV T "FOO")) Use DEFINE-COMPILER-MACRO instead of DEFINE-MACRO in the 6SUPPORT file. If you cannot write your code so it will run in Maclisp at all, you'll have problems until July. But looking at your code for LOOP I don't immediately see that you'd have problems. LABELS in the T compiler seems to be having some problems. I'll fix them as soon as I can. In the meantime I discourage making heavy use of LABELS for things other than iteration or "trivial procedures" (those which refer to no local LAMBDA-bound variables), if you want your code to compile.  Date: Thursday, 10 June 1982 18:41-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: read-line As Norman reported, READ-LINE returns a string for one "line". The default method is to do READC's until a #\NEWLINE is encountered, but this is handled more efficiently by streams open on files or terminals. If you want to read objects in an input line, try (DEFINE (READ-LINE-OF-OBJECTS INPUT-STREAM) (LET ((STREAM (STRING->INPUT-STREAM (READ-LINE INPUT-STREAM)))) (ITERATE LOOP ((L '())) (LET ((OBJ (READ STREAM))) (COND ((EOF? OBJ) (REVERSE! L)) (T (LOOP (CONS OBJ L)))))))) With this definition, if the line has incomplete expressions, you'll get an "end of file in read" error (shouldn't that be "end of stream?" - sigh). Sometime this summer you'll be able to do other things with such conditions using BIND or CONDITION-BIND (like continue reading?) but not yet. As for continuing if the line ends a certain way, you could easily write a loop which simply inspects the string returned by READ-LINE, etc. I agree that this isn't terrific style, but that's a subject for another debate in which I'm unwilling to involve myself at this point.  Date: Friday, 11 June 1982 12:45-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: New VAX T Release I released VAX T version 1.57 yesterday. It has some of the features described in the recent Apollo release notice, but is not completely up to date. One additional feature is worth noting: - (SET (RECKLESS?) T) and (SET (RECKLESS?) NIL) will respectively disable and enable consistency-checking in the calling sequence. This is a temporary kludge, and will be replaced by something more general in the future, but it's kind of fun to play with if you care about timings and things like that. This works on the VAX but not on the Apollo. Painful bugs worth remembering: - GC now has problems, it comes on some bad pointer somewhere and goes into a break loop. Say (RET NIL) to proceed; that might work. Hope no ine depends on the GC yet. - Saying ^D at break level will sometimes do a RESET but sometimes does an (EXIT). Don't use it. - The ^C interrupt works, but avoid doing anything besides (BACKTRACE), (DEBUG), and (RESET) in the break loop. My apologies for these annoyances. I'll get on the trail after my vacation.  Date: 11-Jun-82 2:46PM-EDT (Fri) From: Robert Nix Subject: LOOP macros. To: Chris Riesbeck , T-Discussion at YALE Chris Riesbeck and I have both ported iteration macros to T. These macros provide syntax for writing Knuth-Loops-- that is, the infinite loops with arbitrarily placed top-level exit statements that Knuth describes in his paper "Structured Programming with GOTO Statements". This message is a proposal for merging Chris's and my LOOPs. I'm sending it to T-Discussion for two reasons: a) This macro represents a style of control construct that is in almost universal use at Yale in all dialects of Lisp. Programmers in TLisp, MacLisp, and Franz Lisp all use it. I would guess that, in the U editor, I use it almost as much as I use IF or COND, and quite a bit more than I use MAP. b) T does not provide this construct. The T implementors do not use this construct, and strenuously object to its inclusion in standard T. Why should this macro be included in standard T? Why not? If not, how should this sort of facility be provided in T? Merging the TLisp and Franz Lisp/ELLISP loop ============================================ This is the TLisp loop, as described by Chris: (LOOP (INITIAL -(var val inc)-) (BEFORE -exps-) (WHILE exp) (DO -exps-) (NEXT -(var val)-) (UNTIL exp) (AFTER -exps-) (RESULT exp) ) This is the Franz/ELLISP loop macro: (LOOP (INITIAL v1 e1 v2 e2 ...) (BEGIN -exps-) (CATCH label) ;;; LABEL is a synonym for CATCH (DECLARE ...) ;;; Doesn't generate anything for T yet. (WHILE expr) (UNTIL expr) (INCR i FROM|.IN.|.IN|IN.|IN e1 [TO e2] [BY e3]) (DECR i FROM|.IN.|.IN|IN.|IN e1 [TO e2] [BY e3]) (FOR x IN l) (DO -exps-) (NEXT v1 e1 v2 e2 ...) (RESULT -exps-) ) As you can see, (if you know what all of the keywords mean), the TLisp loop provides a subset of the functionality of the Franz/ELLISP loop. The following changes would have to be made to the F/E loop to make it completely subsume the TLisp loop: 1. The only important syntactic difference is the extra layer of parenthesis surrounding the constituents of the INITIAL and NEXT clauses in TLisp. I happen to like the TLisp syntax, so I'm quite willing to change over to it, and convert all of my code to the new syntax. I thought about expanding the syntax to allow both kinds, but this was too ambiguous even for me. 2. The TLisp BEFORE is called BEGIN in Ellisp. BEFORE is a better name, so I hereby change the name for this construct from BEGIN to BEFORE, with BEGIN accepted as a synonym. 3. The TLisp AFTER clause makes up for a deficiency in TLisp's RESULT clause-- that it takes just one expression, rather than a list of expressions. The F/E Loop doesn't have this problem, so there is no reason for the AFTER clause. I find (LOOP...(AFTER e1 e2) (RESULT e3)) much harder to understand than (LOOP...(RESULT e1 e2 e3)). For this reason, I would rather not implement AFTER. You could take care of this in the TLISP_TO_T conversion. So the proposed loop has the syntax: (LOOP (INITIAL (v1 e1 inc1) (v2 e2 inc2) ...) (BEFORE -exps-) ;;; BEGIN is a synonym for BEFORE. (CATCH label) ;;; LABEL is a synonym for CATCH (DECLARE ...) ;;; Doesn't generate anything for T yet. (WHILE expr) (UNTIL expr) (INCR i FROM|.IN.|.IN|IN.|IN e1 [TO e2] [BY e3]) (DECR i FROM|.IN.|.IN|IN.|IN e1 [TO e2] [BY e3]) (FOR x IN l) (DO -exps-) (NEXT (v1 e1) (v2 e2) ...) (RESULT -exps-) ) The INCR/DECR syntax has been extended to offer support for T's half-open intervals: (INCR i .IN. 0 TO 10) varies i in 0..10 FROM is a synonym for .IN. (INCR i .IN 0 TO 10) varies i in 0..9 (INCR i IN. 0 TO 10) varies i in 1..10 (INCR i IN 0 TO 10) varies i in 1..9 (DECR i .IN. 10 TO 0) varies i in 10..0 FROM is a synonym for .IN. (DECR i .IN 10 TO 0) varies i in 10..1 (DECR i IN. 10 TO 0) varies i in 9..0 (DECR i IN 10 TO 0) varies i in 9..1 STEP is a synonym for INCR, and DOWNSTEP (ugh) is a synonym for DECR. I implemented an ad hoc UNWIND-PROTECT clause in the LOOP I did within Franz, I'll put it back into the LOOP macro as soon as T's UNWIND-PROTECT doesn't cons. If T had Lisp's PROG, then LOOP would be translated into this: (CATCH -exit-label- ; from CATCH. (PROG -prog-vars- ; from INITIAL, INCR, DECR, and FOR. -declaration code- ; from DECLARE, INCR, and DECR. -initialization code- ; from INITIAL, INCR, DECR, and FOR. -before-code- ; from BEFORE. LOOP-TOP -iteration tests- ; from INCR, DECR, and FOR. -body and tests code- ; from DO, WHILE, UNTIL, and NEXT. -step code- ; from INCR, DECR, and FOR. (GO LOOP-TOP) LOOP-EXIT -result code-)) ; from RESULT. But it's actually translated into this TC-compilable T: (CATCH -exit-label- (LET ((var1 init1)) -more-variable-bindings- (LET ((LOOP-EXIT (LAMBDA () -result code-))) (LABELS ((LOOP-TOP (LAMBDA () (IF -exit condition- (LOOP-EXIT) (IF -exit-condition- (LOOP-EXIT) -more-body- -increment and step code- (LOOP-TOP)))))) -before-code- (LOOP-TOP))))) LOOP-TOP is a tail recursive form, so this all compiles into JUMPs. -------  Date: 11-Jun-82 2:50PM-EDT (Fri) From: Robert Nix Subject: What should be in T? To: Chris Riesbeck , T-Discussion at YALE One man's opinion of what should be in T. ========================================= I'd like to pose these questions: - What should be in T? - What should be in the T manual? - What should be outside of T, but in a common T library? - Should there be a common T library? - Should the T manual have a T library section? - What should be in a X->T conversion package? There are several general classes of functions and special forms that are currently in T, or could become a part of T in the near future: 1. Those that must in the T "core", such as CONS, EQ?, STRING-ELT, etc. 2. Those that are trivial combinations of elements of the core, but package functionality that is so basic to our way of reasoning about programs that we would be lost if we had to program without them. E.g. MAP, MEMBER, SUBSTRING, UNWIND-PROTECT, etc.. Most of these functions are only five lines long, but they are very important. Over half of the functions in T fall into this category, and I would expect this proportion to grow. 3. Those that are trivial combinations of elements of the core, do not provide any added functionality, but do provide some creature comfort. An example of this would be a SUBSTRING that takes START and END indices rather than START and LENGTH. 4. Those that are trivial combinations of the elements of the core, do not provide any added functionality, but are there mostly for compatibility with some other Lisp system. For example, the current version of the U editor uses 1-based strings, and I may end up writing a 1-based string package in order to postpone that particular phase of the conversion process. These belong in compatibility packages; they do not belong in T or a general T library. 5. Those that introduce new classes of objects to the T core, such as a set package. 6. Those programming aids that provide non-trivial combinations of elements of the core. These are "mini-interpreters" like FORMAT, sophisticated iteration macros, pretty-printers, error packages, and debugging packages. 7. Those that would be in (6), except that the T implementors don't happen to like them. 8, 9, 10. I've probably missed something... Structuring the manual ====================== Given that the manual has to be printed on a linear medium, I think that there should be at least three separate, up-to-date, printed "views" of the manual available to the users. These views should be generated from the same source text, of course. vol I. The core functions in (1). This should be a 75 page monograph giving an introduction to the fundamentals of T, descriptions of the core functions, and a sketch of the implementations. vol II. The "key" (?) functions in (1), (2), (3), and (6). Wherever feasible, this document should give plausible source code for all of the functions classified as (2). This should be about 300 pages long. vol III. The InterLisp edition, a superset of (II), that contains documentation for all of the standard system, all of the available utilities, compatibility packages with other Lisps, and low-level details of the various T implementations. This should be in looseleaf binder format. Perhaps III should be II + appendices. II is much more static than III. Biased Classification of Riesbeck's Utilities ============================================= This attempt at classification came about after I looked over the utilities that Chris described in his message of a few days ago. Some of these utilities, such as the LOOP and FOR macros, seem like they would be appropriate members of a general T tools library-- i.e. they are of general interest and provide non-trivial functionality, but the T implementors might not want them dirtying up their pristine system. Others, like SUBSET and MAPCAN, are of general interest, have trivial definitions in T, but implement popular programming primitives, and thus should probably be packaged in the standard T system and be described in the "mapping functions" section of the manual. These look like useful utilies, and should be part of the T Tools package: 1. LOOP macro (see my message about consoldating TLisp loop with the Franz/Ellisp loop.) This is a class 7 form (because Jonathan doesn't like it), but it is not subsumed by anything else, so it should be a Class 6. 2. FOR macro. This is falls into the same category as LOOP. These look like useful utilities that should be standard T routines, and I like the names: 1. SUBSET -- (SUBSET fn -lists-) applies fn in parallel to elements of the lists, returns all elements of the first list for which fn returns true. A Class 2 form. 2. := -- The SET mechanism subsumes this, and is much more elegant. On the other hand, I like the name := better than SET, and I like the *-* feature of :=. In Chris's := macro, *-* is bound to the value of the form being set, so that you can write things like: (:= (long-and-hairy-settable-expression) (+ *-* 3)). You can get this same effect with SET, by changing the := macro to generate: (:= x exp) ==> `(SET x (LET ((*-* x)) exp)) Or something of the sort. Of course, this macro should not be called :=, rather it should be called SET*-*, or some other horror. This is a class 3 form. These look like useful utilities that should be standard T routines, but they should be given more T-ish names: 1. APPEND1 and APPEND1! Where did the use of "1" arise, anyway? Class 2 form. 2. (LDIFF list1 list2) returns the portion of list1 before list2, if list2 is a tail of list1. Nice primitive, but the name is not T-ish enough. Also probably want an LDIFF!. Class 2 form. 3. PRELIST -- (PRELIST list n) returns first n elements of list. Also probably want PRELIST!. Class 2 form. 4. MAPCAN -- (MAPCAN fn -lists-) applies fn in parallel to elements of the lists, splices the answers together with NCONC. Class 2 form. These should be flushed during the TLISP_TO_T conversion process: 1. MSG -- (MSG -cmds-) FORMAT seems clearly superior, so the only reason to have this is for compatibility. I think that you should convert calls to MSG to FORMAT in TLISP_TO_T. Class 7 form, that is superseded by a good Class 6 form, so it should be flushed. These already exist, although you may have different semantics in mind. If you're happy with the T definitions, then these should be converted during TLISP_TO_T: 1. ATCAT is SYMBOL-CONC. Class 4 form. 2. ADD1 and SUB1 are 1+ and -1+. Class 4 form. 3. CONSP ==> is PAIR?. Class 4 form. 4. SUFLIST is NTHCDR. Class 4 form. I would like to suggest these: 1. 1+! and -1+!. (1+! x) ==> (SET x (1+ x)) These are TLisp's INCR and DECR, and Jonathan tells me that INCREMENT is already in T. These are Class 2 forms. -------  Date: 11-Jun-82 4:42PM-EDT (Fri) From: Chris Riesbeck Subject: Re: LOOP macros. To: Nix at YALE Cc: T-Discussion at YALE In-Reply-To: Your message of 11-Jun-82 2:46PM-EDT (Fri) I'm all in favor of merging the two LOOPs and am as happy to compromise as Bob Nix appears to be. A few points are not clear. Given (LOOP (INITIAL (v1 e1 inc1) (v2 e2 inc2) ...) ...), which behaves like (DO ((v1 e1 inc1) (v2 e2 inc2) ...) ...), shouldn't the expanded form be (LET ((LOOP-EXIT (LAMBDA () -result code-))) (LABELS ((LOOP-TOP (LAMBDA (v1 v2 ...) ... -increment and step code- (LOOP-TOP inc1 inc2 ...)))))) -before-code- (LOOP-TOP e1 e2 ...))))) That is, LOOP-TOP needs arguments for parallel incrementing. This can't be done with the -increment and step code-. Actually only those variables that are given explicit increment forms need be included with LOOP-TOP, so that if we have (INITIAL (v1 e1) (v2 e2) ...) then LOOP-TOP will indeed have no arguments. While I'm here, a style question. Why is it better to define the LOOP-EXIT separately, rather than with LOOP-TOP in the LABELS? The only difference I can see would be if result-code referred to some other function called LOOP-TOP, but problems like that can still arise. 3. The TLisp AFTER clause makes up for a deficiency in TLisp's RESULT clause-- that it takes just one expression, rather than a list of expressions. The F/E Loop doesn't have this problem, so there is no reason for the AFTER clause. I find (LOOP...(AFTER e1 e2) (RESULT e3)) much harder to understand than (LOOP...(RESULT e1 e2 e3)). For this reason, I would rather not implement AFTER. You could take care of this in the TLISP_TO_T conversion. Actually, that was a feature not a bug. It's trivial enough to handle (RESULT e1 e2 e2), and the first version I did in T did so (it may still do so). I thought (and still think) that it's clearer to separate out what's done at the end of the loop from what's returned. For example, I think that (LOOP ... (AFTER e1 ...)) with no RESULT clause should have an undefined value. The current implementation of TLisp's LOOP in T guarantees NIL, I believe, but I'm softer-hearted than the T implementors. I vote that AFTER be left in, along with multi-expression RESULTs, so that various religious fanatics can take their choice. -------  Date: 11-Jun-82 5:54PM-EDT (Fri) From: Robert Nix Subject: Re: LOOP macros. To: Chris Riesbeck Cc: T-Discussion at YALE In-Reply-To: Riesbeck's message of 11-Jun-82 4:42PM-EDT (Fri) Given (LOOP (INITIAL (v1 e1 inc1) (v2 e2 inc2) ...) ...), which behaves like (DO ((v1 e1 inc1) (v2 e2 inc2) ...) ...), shouldn't the expanded form be (LET ((LOOP-EXIT (LAMBDA () -result code-))) (LABELS ((LOOP-TOP (LAMBDA (v1 v2 ...) ... -increment and step code- (LOOP-TOP inc1 inc2 ...)))))) -before-code- (LOOP-TOP e1 e2 ...))))) That is, LOOP-TOP needs arguments for parallel incrementing. This can't be done with the -increment and step code-. My main technical objection to this implementation is that the current values of the step variables are not accessible to the exit clause. You could rewrite it so that they are, although getting TC to munge that form correctly may take some trial and error. I also have a religous objection: A FEATURE of LOOP is that all forms are evaluated sequentially, NOT in parallel. I like this very much-- I do not recall ever having wished that the variables or parameters of ANY special form were initialized or updated in parallel. For example, I have often wished that LET implemented sequential assignment. The only reason I can see for it being parallel is to allow it to be used reliably within macros. E.g., if LET were sequential, then the macro: (define-macro (foo a b) `(let ((x ,a) (y ,b)) ...)) would generate something equivalent to the following when invoked with (foo baz x): (let ((x baz)) (let ((y x)) ...)) which is probably not what you wanted. Outside of this one glitch, I've found a sequential LET to be far more useful. In the case being discussed here, I could not imagine writing code where I cared whether that the rebinding of the inci's was parallel or sequential. But, all of the other bindings within LOOP are defined to be sequential, so these should be defined that way too. Actually only those variables that are given explicit increment forms need be included with LOOP-TOP, so that if we have (INITIAL (v1 e1) (v2 e2) ...) then LOOP-TOP will indeed have no arguments. So you want sequential initialization, but parallel update? While I'm here, a style question. Why is it better to define the LOOP-EXIT separately, rather than with LOOP-TOP in the LABELS? The only difference I can see would be if result-code referred to some other function called LOOP-TOP, but problems like that can still arise. Its not a matter of style-- this compiles without CONSing a closure, while the LABELS you suggest doesn't in the current, imperfect, TC. In any case, I don't think that its very important to worry about style in the code generated by a macro expansion. I vote that AFTER be left in, along with multi-expression RESULTs, so that various religious fanatics can take their choice. I give in. -------  Date: 11-Jun-82 5:12PM-EDT (Fri) From: Chris Riesbeck Subject: Re: What should be in T? To: Nix at YALE Cc: T-Discussion at YALE In-Reply-To: Your message of 11-Jun-82 2:50PM-EDT (Fri) I agree with most of what Bob Nix had to say, except the following: Biased Classification of Riesbeck's Utilities ============================================= 1. APPEND1 and APPEND1! Where did the use of "1" arise, anyway? Class 2 form. From NCONC1 in UCILisp, presumably for "NCONC one element." I sometimes like CONSR for "CONS right" but then it gets confusing which order the arguments should be in. 1. MSG -- (MSG -cmds-) FORMAT seems clearly superior, so the only reason to have this is for compatibility. I think that you should convert calls to MSG to FORMAT in TLISP_TO_T. Class 7 form, that is superseded by a good Class 6 form, so it should be flushed. Sorry -- I think MSG is clearly superior. I find it much easier to write (MSG T "X is " X " and Y is " (E (SPRINT Y 1)) T) than (BLOCK (FORMAT SO "~%X is ~S and Y is ") (SPRINT Y 1) (FORMAT so "~%")) for several reasons: 1. I like having things appear in the order in which they come out. 2. All those special characters in FORMAT really slow down my typing. 3. I like to mix in special printing with (E exp) without leaving the MSG form. 4. MSG has a tabulation feature -- (T n) moves to column n. If this is in FORMAT, it's not documented. 5. As implemented in T, MSG is open-ended. The user can define his or her own command forms, e.g., (PP exp) to replace (E (PP exp)), or (RJ exp) to right-justify exp. I don't see how to add this flexibility to FORMAT. I realize that people who work with PRINTF have FORMAT-style output in their blood, and I'm happy to let them continue, but there's no way I'm flushing MSG. I actually thought for a while about translating MSG to FORMAT and realized how difficult that would be because MSG is so much more powerful. I have changed the names of some things, e.g., (E exp) is actually (DO exp) and (T n) is (COLUMN n), but on the whole I like MSG the way it is. Note that MSG currently has no stream argument. My current plan is to fix this with (STREAM exp), with STANDARD-OUTPUT as the default. This would allow (but why would one want it?) changing streams in mid-message. These already exist, although you may have different semantics in mind. If you're happy with the T definitions, then these should be converted during TLISP_TO_T: 2. ADD1 and SUB1 are 1+ and -1+. Class 4 form. 3. CONSP ==> is PAIR?. Class 4 form. 4. SUFLIST is NTHCDR. Class 4 form. While I like 1+ and -1+, TLisp doesn't. I needed ADD1 and SUB1 for compatibility with the output of TLISP_TO_T, not for future use. CONSP is not PAIR?, because it returns the argument if it's a pair, allowing me to write dirty code like (OR (CAR (CONSP X)) X). You can take it out of T and I can't argue on aesthetic grounds, but I know a number of people who will borrow it from me. SUFLIST was obviously to be parallel to PRELIST, particularly because they tend to be used to together. I'd like to have it as a synonym. The only major disagreement is with MSG and FORMAT. There are just two worlds here, systems programmers and non-sps. -------  Date: 12 June 1982 03:36-EDT From: Kent M. Pitman Subject: Retrying failed mail (sorry for the silly text at the top, I'm too lazy to strip it) To: T-DISCUSSION-TRANSCRIPT at MIT-MC, DEUTSCH at PARC-MAXC, JIM at WASHINGTON, MEEHAN.UCI at UDEL-RELAY Date: 12 Jun 1982 0309-EDT From: Yale Local Mailer To: Kmp Re: Bad network mail Unable to send PS:NETMAIL.CPY.7 file to the following hosts: WASHINGTON JIM UDEL-RELAY MEEHAN.UCI MIT-MC T-DISCUSSION-TRANSCRIPT KMP PARC-MAXC DEUTSCH Responses from remote mailer(s): Queued ARPANET mail for WASHINGTON via YALE...open Connection refused Queued ARPANET mail for UDEL-RELAY via YALE...open Connection refused Queued ARPANET mail for MIT-MC via YALE...open Connection refused Queued ARPANET mail for PARC-MAXC via YALE...open Connection refused Text of message: Mail-from: ARPANET site MIT-MC rcvd on Sat Jun 12 03:04:33 Date: 12 June 1982 03:02-EDT From: Kent M. Pitman To: Riesbeck at YALE cc: T-Discussion at YALE, McDermott at YALE, Guy.Steele at CMU-10A Date: 11-Jun-82 5:12PM-EDT (Fri) From: Chris Riesbeck ... 1. APPEND1 and APPEND1! Where did the use of "1" arise, anyway? Class 2 form. From NCONC1 in UCILisp, presumably for "NCONC one element." ... ----_ It's funny how things get their names. I found this etymological note pretty amusing. I have this as nth hand information I think from Rees who I think got it from Drew, so maybe one of them correct me if I'm wrong, but this is the story I know... Once upon a time there was an operator named CONC which destructively joined two lists. Then someone thought that there should be an nary version, so made NCONC. CONC eventually went away, so there was just NCONC and APPEND. People assumed the "N" meant destructive, hence the badly named NREVERSE, intended to mean destructive REVERSE instead of nary REVERSE (whatever that would be), which the morphemes in its name should by right imply. So though NCONC doesn't do what CONC used to, it's still interesting to think of UCILisp having de-nary-ized NCONC without removing the "N" ... Probably if they'd known, they'd have wanted to call it CONC1 and not NCONC1... Drew, did I get my history right? Hope so. -kmp ps This note isn't meant to set off any big arguments 'bout naming -- just to add a note of humor to everyone's day...  Date: 12-Jun-82 12:49PM-EDT (Sat) From: Chris Riesbeck Subject: [Meehan: The use of "1"] To: T-Discussion at YALE *** Forwarded Message Follows **** Mail-from: ARPANET site UDEL-RELAY rcvd on Fri Jun 11 23:22:59 Date: 11 Jun 82 16:59:09-PST (Fri) From: Jim Meehan To: riesbeck.yale at UDel-Relay Subject: The use of "1" Via: UCI; 11 Jun 82 23:16-EDT ... as in APPEND1 and NCONC1. These come from unimaginative programmers who wanted a name similar to APPEND and NCONC, that's all. There was no intention of having it mean "APPEND one element..." or anything sensible. It's a style going back to assembly programming, where you had an "entry point" such as SQRT, and you needed auxilary, internal labels: SQRT1, SQRT2, etc. The "best" example I can remember from LISP.MAC is FIX which begat FIX1 which begat FIX1A, which is the most useful of the three. *** End of Forwarded Message **** -------  Date: 15-Jun-82 3:52PM-EDT (Tue) From: Drew McDermott Subject: PROXY Syntax To: T-Discussion at YALE As far as I can see, proxies behave much like handlers. However, the former are implemented via an operation PROXY, while the latter are implemented by the use of (=> ...) clauses in ENTITY definitions. This asymmetry should be eliminated, either by providing a HANDLER operation; or by providing (==> proxy) clauses; or both. I favor flushing PROXY as an operation, if for no other reason than that it would never have a default. Also, the alternative allows constructs like (ENTITY ... ... (==> PROX1) (=> HANDLE) (==> PROX2) ) which would mean, "Send operation to PROX1; if it doesn't like it, try HANDLE; if it doesn't like it, try PROX2." -------  Date: 22-Jun-82 1:59PM-EDT (Tue) From: John R. Ellis Subject: Re: prettyprinting To: Riesbeck at YALE Cc: T-Discussion at YALE In-Reply-To: Riesbeck's message of 22-Jun-82 11:51AM-EDT (Tue) ELLISP uses a very well written pretty printer from MIT (I forget right now who wrote it). It is fast enough and robust enough so that it is the default printer in ELLISP (amazing how your work habits change when things are always printed out pretty). Some of its features are: optional circularity detection list length elision nesting elision fairly powerful extensibility optional printing of lists in columns (does pretty well). When Ruttenberg and I first got GPRINT, we were able to write a print method for GPRINT that handled records (structures) in less than an hour; with another hour of work, we made it really pretty. GPRINT is by far the best pretty printer I have seen; why settle for less? GPRINT is written in fairly clean Maclisp (sources in [RES]GPRINT.LSP). It should be only a day or two's work to port it to T. If you're interested in how well it does, see an ELLISP user for a demo, or run ELLISP yourself. -------  Date: 24-Jun-82 3:10PM-EDT (Thu) From: John R. Ellis Subject: Re: Status Returns To: "Rees@YALE-CS" at YALE Cc: Baldwin at YALE, T-Discussion at YALE In-Reply-To: Rees's message of Thursday, 24 June 1982 14:39-EDT The Mesa people have had the most experience with handling "exceptional conditions"; I would recommend that someone dig up their most recent papers (maybe Alan or Mike Fischer can get them) to see what they have to say about "normal conditions" versus "exceptional conditions". There are good arguments for both styles (returning a unique value versus raising an exception). The constructs Kent implemented/proposed last summer are very similar in style to Mesa constructs. The two important arguments against using exception handling in "normal situations" (reading end of file is a "normal situation", as is often not finding a file): 1. In large systems, it is very hard to avoid the physical and logical separation of handlers and the code that could potentially raise conditions. Kent's stuff, like Mesa, does not solve this. 2. Without exceptions, the programmer is forced to deal with the possibility of "failure" explicitly, immediately. Xerox's experience is that in the long run this produces much cleaner, better structured systems. The tendency with large systems built on exceptions is to delay providing clean and robust handlers until very late in the development, by which time it is too late to do it correctly. Of course you could do the development "right", but in practice this doesn't happen. This is an important sociological point about programming with exceptions. As I understand it, the general feeling at Xerox now is to use exceptions only for those things that should never happen "normally" (disk failure). Opening a file can fail "normally" and should not be handled with exceptions. I don't fully agree with these arguments, but they should be taken seriously. -------  Date: 21-Jun-82 5:52PM-EDT (Mon) From: Chris Riesbeck Subject: TLisp to T conversion To: T-Discussion at YALE Status report: Good news and Bad news. The good news is that I managed to get Micro-TaleSpin (from Schank and Riesbeck, Inside Computer Understanding; source code in [RES]TEN.LSP) sort of running on the Apollo. It took basically a day and a half. Half a day to upgrade TLISP_TO_T to handle everything in Micro-TaleSpin and another day to fix everything that TLISP_TO_T couldn't. The conversion was fairly easy, even though Micro-TaleSpin makes very heavy use of EVAL to do a form of data-driven programming. Some simple LAMBDA-wrapping took care of this. But it should be remembered that Micro-TaleSpin, like all the programs in the book, was written in a very restricted subset of Lisp, intended to be relatively portable. E.g., it took me a day and a half to get the much smaller Micro-Eli parser going in John Allen's TLC-Lisp on a Z-80. Real programs will be a lot worse, not because they are biggger, but because there are an awful lot of functions in TLisp. The bad news is that Micro-TaleSpin doesn't run that well. It's a cons-intensive program, and T doesn't really seem to be able to handle it. There are four demonstration examples and it can't do all of them without getting a HEAP-OVERFLOW crash. In fact, it can't do the last example at all, which surprised me, because it didn't seem like it was that big a deal. Can the boundaries be extended? Would that help? I hear a lot of disk head movement as it is. Running time was also pretty bad. The interpreted version (with macros expanded) on the 20 took about 12 seconds real time for the first example, with a load average of 3. The Apollo version took 71 seconds, with no other process running. Since Micro-TaleSpin uses a number of utility macros (LOOP, FOR, and some readmacros), I can't compile it to see how things would improve. -------  Date: 22-Jun-82 11:32AM-EDT (Tue) From: Chris Riesbeck Subject: Additions to T utilities To: T-Discussion at YALE Bob Nix's favorite function, MSG, has been extended to take (MSG ... (TO stream) ...) to redirect output (a local effect to the end of the MSG only), as well as (BIND ((*MSG_STREAM* ...)) ...) to affect a bunch of messages if they didn't explicitly say where they were going. Also added (ERRMSG -cmds-) => (MSG (TO error-output) -cmds- (DO (ERROR))) and (TTYMSG -cmnds-) => (MSG (TO standard-output) -cmds-) MSG, ERRMSG and TTYMSG are macros that expand into (LET ((msg_out_stream *MSG_STREAM*)) -command_expansions-) where output commands expand to msg_out_stream and TO expands to (SET msg_out_stream ...). -------  Date: Wednesday, 23 June 1982 23:46-EDT From: Jonathan Rees To: T-Discussion at YALE, Apollo-Users at YALE Subject: T-Discussion log The T-Discussion transcript, which formerly resided in T-DISCUSSION.TXT on the Ed machine, has been moved to the directory, consistent with the research machine, as it should have been all along. Thus its homes are now: Machine Pathname YALE-RES T-DISCUSSION.TXT YALE-CS T-DISCUSSION.TXT MIT-MC LSPMAI; T MAIL  Date: 22-Jun-82 11:51AM-EDT (Tue) From: Chris Riesbeck Subject: prettyprinting To: T-Discussion at YALE Easy questions, but not of trivial consequence for those of us who intend to produce human-readable files: Is there some way to redirect PP's output? Is there some way to change PP's left margin? Harder question: What are the future plans for PP? I would hope that the real one will have convenient hooks for the user, data-driven by particular function names. TLisp makes it fairly easy to control indentation in expression-units, e.g., you can easily say that DE should have the format (DE name arg_list body) or (DE name arg_list body) i.e., indent under DE or under name, although you have to drop to user code to get something like (DE name arg_list body) i.e., indent 2 spaces. On the other hand, (SPRINT exp left_margin) makes the user code fairly straightforward. TLisp's PP has another feature that's useful; you can specify that (name exp) prettyprint as exp, i.e., an inverse readmacro. Since many readmacros, including ', behave this way, it can make PP'ed forms much more readable. However, it can make some straightforward implementations of PP quite non-straightforward, since short expressions that fit on one line can no longer be just printed, and the size of an expression is not its FLATSIZE. Drew says he has worked out a fairly nice prettyprinter. Perhaps it can be converted. -------  Date: Thursday, 24 June 1982 11:10-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: files T has moved to the ed machine. The sources and everything else (such as the bug archive T-BUGS.TXT) have moved. The directory and file names remain the same.  Date: Thursday, 24 June 1982 11:49-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: files Date: 24-Jun-82 11:27AM-EDT (Thu) From: Chris Riesbeck ... That doesn't make sense. I thought I made myself clear, but I meant to say: if you used to look on the research machine for a file BAR.BAZ, you should now look on the ed machine for the same file under the name BAR.BAZ. The ED may be a fine place for archiving (for the summer), but recent relevant stuff needs to be on both. Okay, T-Bugs will also be maintained on the research machine; I just made the UDB change. But what constitutes "recent relevant stuff?" We're not using the ed machine for archiving; we're doing our work there. There's not enough disk space (until the new disk on the research machine is installed) to maintain everything both places; it's a pain in the ass besides. I'll assume that by "recent relevant stuff" you mean only the mail archives for T-Discussion and T-Bugs (and maybe T-Users?), not the sources, documentation, or history files.  Date: Thursday, 24 June 1982 14:39-EDT From: Jonathan Rees To: Baldwin at YALE Cc: T-Discussion at YALE Subject: Status Returns Well, there's already OPEN and MAYBE-OPEN, the first of which errs if it can't return a valid stream, the second of which is supposed to always return something without erring. Perhaps the thing to do is to make MAYBE-OPEN return some sort of status indicator. Right now it probably just returns () if it doesn't win. Problems... (a) What is a "status indicator"? Is it a symbol? Is it an object which is the value of some variable? (b) To what extent can this be made system-independent? I'm sure that e.g. Unix and VMS have many conditions which correspond to conditions on the Apollo. (c) Why is OPEN special? Will it be necessary for every such routine, e.g. RENAME-FILE or DELETE-FILE, to come in two flavors? What about READC and PRINT? I would suggest that OPEN really is different, and that it makes sense for there to be both OPEN and MAYBE-OPEN, because MAYBE-OPEN is so useful. I'm probably wrong. But having two versions of everything is clearly wrong. Maybe OPEN should just be defined to return () if the file wasn't found, and either return () or err if there was some other problem, and we can eliminate MAYBE-OPEN. I don't know; having OPEN always return something that answers true to STREAM? is a nice property to preserve. I guess I think that status returns are kind of weird. Often you DO want the system to raise an exceptional condition and handle it in an "ordinary" way (e.g. print an error message, and either abort, or avoid proceeding until the problem has been fixed). I agree that the notation can be quite awkward but I don't think that has to be the case. Not yet implemented in T are objects called "conditions" and ways to bind condition-handlers to them. E.g. (CONDITION-BIND ((FILE-ERROR (LAMBDA (PATHNAME ERROR-SUBTYPE) (SELECT ERROR-SUBTYPE ((FILE-IS-LOCKED) ...) ...)))) (OPEN PATHNAME)) Note that the exception handler is pretty close to the place where you need it, and you get all that nice lexical environment. You can pretty easily do a throw to get where you need to go. Compare this with (LET ((PROBE (MAYBE-OPEN PATHNAME))) (COND ((NULL? PROBE)...) ((EQ? PROBE FILE-IS-LOCKED) ...) ... ((STREAM? PROBE) ...))) I don't know. The second may be more concise, but I'm not sure it's cleaner, and I'm not sure you want to bother checking to make sure you won on EVERY system-interface call. This could be pretty tedious with things like READC (you already need to check for *EOF*). Kent worked on this last summer; I'll provide more details on proposed syntax and features for conditions in the future. In any case it's not implemented yet. For now you might want to use Nat's DEFINE-APOLLO stuff directly; talk with him.  Date: Thursday, 24 June 1982 11:32-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: prettyprinting Is there some way to redirect PP's output? Yes. Call PRETTY-PRINT directly, giving it some stream as second argument. Note that PP is defined approximately as follows: (DEFINE (PP FORM) (FRESH-LINE STANDARD-OUTPUT) (PRETTY-PRINT (IF (NONVALUE? FORM) (NONVALUE->VALUE FORM) FORM) STANDARD-OUTPUT) (FRESH-LINE STANDARD-OUTPUT) T) Is there some way to change PP's left margin? Yes, again by calling PRETTY-PRINT directly. It uses the current horizontal position as its left margin. What are the future plans for PP? It has obviously been our (the implementors') position so far to provide only the bare minimum in the way of a pretty-printer. It seemed to us not only that our effort was better spent elsewhere, but that in the best of possible worlds text formatting, which is what pretty-printing is, after all, should be done using an appropriate tool: a text formatting system, such as an editor (which might or might not be written in Lisp). Conventional pretty-printers have always seemed to us inappropriately placed in the structure of a programming system, and modularity has sufferred because the same functionality has to be duplicated in both the editor and lisp i/o system. The editor ought to be the SAME as the i/o system, and the editor should know how to pretty-print. I realize that this is not the best of possible worlds, and that someone may want to implement an intermediate solution. I encourage this and would be glad to consult but have to say I have practically no interest in the project at the current time. The Waters printer (GPRINT) would probably be a good place to start.  Date: Friday, 25 June 1982 16:12-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: VAX T 1.70 released VAX T version 70 is released. Features and bug fixes include: - Structures and delays are in, as described in the manual. - READ-LINE works now. - Fixed problem with LOAD whereby input stream didn't get closed when the load was thrown out of (e.g. aborted with a RESET). - New streams TERMINAL-INPUT and TERMINAL-OUTPUT exist. For now these are pretty much the same as STANDARD-INPUT and STANDARD-OUTPUT, but the idea is that the latter are intended to be re-bound, and the former aren't. Watch this space for future plans. The "T" in (FORMAT T ...) now means TERMINAL-OUTPUT. - Procedure names are tracked somewhat more reliably now. That is, you should see things like #{Procedure #x37EFC} printed a little less often, and #{Procedure FROBAZZ} a little more often. - DEBUG has new commands W (which does a WHERE-DEFINED on the current frame) and R (like Maclisp's DEBUG's R - return (throw) a value to this frame). Still not very useful, but getting there. - The long names for the arithmetic routines (ADD, SUBTRACT, MULTIPLY, etc.) are defined now. MIN and MAX exist. They still aren't generic, but that will come. Some of these items have been previously reported for the Apollo version, or are true and unreported. When version 71 or 72 comes along we'll try to get the VAX and Apollo versions really in sync again, so a release notice will be a release notice.  Date: 1-Jul-82 1:59PM-EDT (Thu) From: Chris Riesbeck Subject: [Rees: TC bug - CERROR] To: T-Discussion at YALE From Rees: I think the compiler would do better ... if you used LET's where possible (that is, where there's no recursion involved) [instead of LABELS]. What is and what will be the status of LABELS in T? Are the current problems with it in the compiler indicative of second-class status (like Lisp's labelled LAMBDAs), or just growing pains in handling a useful but tricky construct? I had assumed that LABELS was in general a good thing, not an exotic form, and that stylistically (LABELS (((F1 ...) ...) ((F2 ...) ...) ... ((FN ...) ...)) ...) was preferrable to (LET ((F1 (LAMBDA (...) ...))) (LET ((F2 (LAMBDA (...) ...))) ... (LET ((FN (LAMBDA (...) ...))) ... ))...) Although the latter might be more efficient and it does say what depends on what, I find the former easier to read, partly because it's not so nested and partly because LABELS supports a function-call-pattern syntax and LET doesn't (does it? How does (LET (((fn -args-) -exps-) ...) ...) look to people?). So, what is the status of LABELS supposed to be? -------  Date: Thursday, 8 July 1982 17:17-EDT From: Jonathan Rees To: "Meehan@YALE-RES" at YALE Cc: T-Discussion at YALE Subject: append I agree completely about your comment that the status-quo APPEND is "wrong". But its intent is sort of in the right direction, in the sense that if you're not doing rplaca's or rplacd's you would like to able to share structure with the arguments wherever possible. The most general way to do this might be if APPEND ignored all trailing () arguments, and shared the last non-() argument with the result. E.g. (APPEND A B '() '()) would return a list one of whose subtails is B. Maybe there should be two versions? I don't see why the last argument should get copied unless it needs to be. If you want to make sure the result is newly-consed one might be required to say (COPY-APPEND ...). I dunno. I guess the reason things are the way they are is that I didn't feel like thinking about it a lot when I wrote it. The definition of APPEND becomes more complicated anyhow when you start allowing other sequence types, like strings, vectors, and lazy lists. There might even be a version of APPEND which returned a sequence which shares structure with all the arguments, so (SET (HEAD (SHARED-APPEND A ...)) FOO) would clobber the head of A (if A was non-empty).  Date: 9-Jul-82 12:10PM-EDT (Fri) From: Drew McDermott Subject: append To: T-Discussion at YALE I vote with the structure sharers on whether APPEND should copy everything. The dangers of structure sharing are oversold, especially since APPEND is supposed to be used for expressions that are never to be RPLAC'd. As far as the "cheap memory" argument goes, what structure sharing saves is garbage collection, not storage. (Granted, in T this is like rearranging the deck chairs on the General Belgrano.) I would argue for the abolition of the (APPEND l NIL) idiom for copying l. There should be a top-level copy primitive. (I don't see one in my T manual.) The only commitment APPEND should really make is that it won't RPLAC anything. No one should depend on its copying lists followed by ()s, or on its not copying them. -------  Date: Thursday, 8 July 1982 17:50-EDT From: Jonathan Rees To: "Meehan@YALE-RES" at YALE Cc: T-Discussion at YALE Subject: predicates There is a comment in the manual (p. 27) which expresses (rather poorly) my dissatisfaction with the MEM/ASS/... series of things. It is quite true that an underlying LAMBDA is being hidden, and the whole thing is misleading and inappropriately modularized. I had planned to think about these iterators more thoroughly later this summer; another hard problem I've punted on. No endorsement implied. The basic operations of interest here go basically like this: DEL - filter - give me a sequence, same as original, with objects (or first object) answering true to predicate, removed. MEM - tail - find me a tail of the sequence satisfying some predicate. ASS/RASS - locate - find me a component of the sequence satisfying some predicate. POS - position - give me the index of a component satisfying a predicate. Problem is that the predicate wants to be a closure, but we don't want to cons it. Two kinds of things would make it easier to approach the problem and explore possible solutions: (a) Stack-allocated procedures. I might have done something more general earlier if I hadn't had to worry about closure consing. (b) Related to this, and quite a bit harder, is automatically tranforming (FOO (LAMBDA (X) ... Y ...) ...) to (FOO-PRIME Y (LAMBDA (X Y) ... Y ...) ...), to avoid consing the closure (whether in the heap or the stack). (The problem is more general than than that even; spreading the components of what ought to be an aggregate on the stack, rather than passing an aggregate, is the same kind of situation. (FOO (CONS X Y) ...) vs. (FOO-PRIME X Y ...).) You're not overreacting; I just should have made my dissatisfactions and future plans more explicit in the manual. I've tried to do this elsewhere, with limited success.  Date: 1-Jul-82 5:19PM-EDT (Thu) From: Nathaniel Mishkin Subject: Different Structure Macro To: T-Discussion at YALE I've written a modified version of DEFINE-STRUCTURE-TYPE called DEFINE-CSTRUCTURE-TYPE. The difference is that the names have ":"s instead of "-"s (e.g. rtype-field => rtype:field) and there is a constructor function which takes positional initializers (e.g. (rtype:new val1 val2 ...)). THe compiled version is running on the Apollo. It is in /tools/t/utils/defcstruct.bin A reasonable structure printer is on the way. -- Nat -------  Date: 24-Jun-82 11:27AM-EDT (Thu) From: Chris Riesbeck Subject: Re: files To: "Rees@YALE-CS" at YALE Cc: Mcdermott at YALE, Odonnell at YALE, T-Discussion at YALE In-Reply-To: Your message of Thursday, 24 June 1982 11:10-EDT T has moved to the ed machine. The sources and everything else (such as the bug archive T-BUGS.TXT) have moved. The directory and file names remain the same. That doesn't make sense. The ED machine is not the primary source for anyone in AI, and T-BUGS (and recent T-DISCUSSIONs), being the only source of up-to-date documentation on T, are too important to keep on one machine anyway. This is even more true now with the presumable influx of new users to follow the arrival of the new Vaxes. The ED may be a fine place for archiving (for the summer), but recent relevant stuff needs to be on both. -------  Date: Friday, 9 July 1982 12:27-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: APPEND I agree completely with Drew's arguments about APPEND, although, diplomatically, I would probably agree to support a copying version (what to call it? COPY-APPEND ?). I believe that one generally knows that the result of APPEND isn't going to be RPLAC'ed. I personaly have NEVER been screwed by shared structure, but I'd be willing to grant that my coding and debugging styles are atypical. If COPY-LIST isn't in the manual, it's a bug. (COPY-LIST list) returns a "top-level" copy of list, like (APPEND list '()) would in Lisp. T makes no guarantee that (APPEND list '()) will copy the list. (This should obviously be in the manual.)  Date: Friday, 9 July 1982 14:35-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: [ ] { } I want to change the status of the four special characters [ ] { and } in the standard T syntax to be no longer defined as "constituent" (i.e. extended alphabetic) characters. This means that where before one could write e.g. [FOO] to notate a symbol whose pname is "[FOO]", one would now need to say \[FOO\]. For now, they won't be defined to be anything else (I haven't committed to anything), it's just that it would be nice for people to not depend on their alphabeticness, or at least to be explicit in setting their syntax, e.g. with (SET (SYNTAX #\[) (SYNTAX #\A))). Note that at some point in the future one will probably need to specify special read syntax in a file's HERALD somehow, rather than in random top-level (SET (SYNTAX ...) ...) forms. This facility still under development. Any serious objections to this change? I realize that "locking down" special characters for weird syntax is to be avoided, so I could probably be talked out of it.  Date: Thursday, 1 July 1982 13:23-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: TC hint Defining the LISP: logical name should make TC a little happier in some cases. This tells Maclisp where to get the hardware "site name" from, and any autoloadable packages (like CERROR) that it might need. DEFINE LISP:  Date: Thursday, 1 July 1982 14:21-EDT From: Jonathan Rees To: Riesbeck at YALE Cc: T-Discussion at YALE Subject: LABELS LABELS has first-class status in T. The intent is to support it with glorious grace, style, and efficiency. The compiler has a lot of problems with it right now. I have a lot of things to do, and fixing LABELS is high on my list, but there are other things I'd like to work on more. When I suggest that one might rewrite code to make the compiler work, I almost invriably mean this as an admission of a compiler bug, and merely say this so that YOU can get work done now, and not have to wait for me to get around to fixing the compiler - which I will eventually. I'm sorry if I haven't made clear what I consider to be bugs, and what to be features, of the T compiler. I had thought all this was implicit.  Date: Friday, 2 July 1982 00:05-EDT From: Jonathan Rees To: T-Discussion at YALE, T-Users at YALE, Apollo-Users at YALE Subject: T-Users There is now a T-Users mailing list. No one protested when I first suggested the idea of its existence, so it has become an accomplished fact. If you are a regular T user and want to hear about releases, new features, and bug fixes as they happen, you should be on the T-Users mailing list. Add yourself, or ask me to add you. If you are on T-Discussion now but don't really care about all the weird things that tend to be discussed there, only about the state of T, please feel free to take yourself off of T-Discussion or to ask me to do it. Mail to the T-Users distribution list will also appear in the files T-USERS.TXT on the research and ed machines.  Date: 14-Jul-82 5:49PM-EDT (Wed) From: James R. Meehan Subject: [Rees: ALIKE? bug and question] To: T-Discussion at YALE *** Forwarded Message Follows **** Date: Wednesday, 14 July 1982 15:35-EDT From: Jonathan Rees To: Meehan at YALE-RES Cc: T-Bugs Subject: ALIKE? bug and question Date: 14-Jul-82 9:07AM-EDT (Wed) From: James R. Meehan Re: ALIKE? bug and question Cullingford and I tried (ALIKE? = '(1 2 3) '(1 2 3)) and T blew up, saying that something wasn't a fixnum. ALIKE? is fixed in the source now. The predicate argument will only be applied to the leaves, thus it doesn't need to be a "universal" (i.e. it doesn't need to defined in the case where either arg is a pair). Am I correct in assuming that the difference between ALIKE? and a two-arg-list EVERY is that ALIKE? looks at all the leaves whereas EVERY look only at the CARs? I.e., (ALIKE? = '(1 2 (3 4) 5) '(1 2 (3 4) 5)) => T but (EVERY = '(1 2 (3 4) 5) '(1 2 (3 4) 5)) => ERROR (can't use = on non-numbers) Yes ALIKE? and EVERY? are similar but I think ALIKE? assumes that the "predicate" is an equality predicate, because it "optimizes" the case where its two args are EQ? (it is assumed that (PRED x y) => (EQ? x y) no matter what PRED is, as long as PRED is an "equality predicate"). E.g. (EVERY? < '(1 2) '(1 2)) returns false while (ALIKE? < '(1 2) '(1 2)) returns true (!) (only because = fixnums happen to be EQ?). The list-manipulation routines and the s-expression manipulation routines are not parallel sets, but they probably should be, to the extent possible. E.g. there should be things equivalent to ANY and EVERY for s-expressions. As I said before, this part of the system is quite incomplete and poorly-thought-out at the moment. *** End of Forwarded Message **** OK. It looks like (ANY pred . lists) and (EVERY pred . lists) should default to elements of lists (i.e., top-level CARs), and there should be (ANY-LEAF pred . lists) and (EVERY-LEAF pred . lists) that work on atomic CARs (i.e., they keep taking CARs until they reach an atom, then they call the predicate). Problems: 1. What if the lists aren't isomorphic, so that one has an atom where another has a list? Options: define that as an error (probably too draconian), or define that as having a NIL result. 2. Do we also need a version of ANY and EVERY that allow non-isomorphic parameters? Maybe not -- let the user write his own. -------  Date: Friday, 6 August 1982 13:59-EDT From: Jonathan Rees To: T-Discussion at YALE Subject: NEWLINE and FRESHLINE Currently: NEWLINE FRESH-LINE READ-LINE Formerly: NEWLINE FRESHLINE READLINE Perhaps: NEW-LINE FRESH-LINE READ-LINE But cough: #\NEW-LINE #\FORM-FEED #\BACK-SPACE SET-UP CLEAN-UP Maybe: NEW-LINE FRESH-LINE READ-LINE #\NEWLINE #\FORMFEED #\BACKSPACE SETUP CLEANUP Flame.  Date: 6-Aug-82 2:47PM-EDT (Fri) From: James R. Meehan Subject: newline et al To: T-Discussion at YALE I vote for NEW-LINE, FRESH-LINE, READ-LINE, #\NEWLINE, #\FORMFEED, #\BACKSPACE. Also, am I imagining things, or was there once a convention like #\CONTROL-A, #\CONTROL-B, etc.? Sounds handy. Also, what's #\NEWLINE on a "carriage return + line feed" machine? -------  Date: Saturday, 7 August 1982 09:56-EDT From: Jonathan Rees To: Meehan at YALE Cc: T-Discussion at YALE Subject: newline et al From: James R. Meehan ... what's #\NEWLINE on a "carriage return + line feed" machine? The general idea is that T's I/O system should try, within reason, to provide an operating-system-independent file model, one in which a file consists of a sequence of "lines" or "records", each of which is a sequence of characters. Doing a READC at the end of a record would cause READC to return #\NEWLINE (a character not necessarily in the actual machine's character set; conceptually not even a character at all (although making it be one makes it possible to put it in a string; a somewhat dubious feature)). This means folding return+linefeed into a single newline token (character). Consider the following scenario: (DEFINE (SUCK STREAM L) ; READC from a file until EOF is found, and (LET ((C (READC STREAM))) ; return a list of the characters read. (COND ((EOF? C) (REVERSE L)) ; Thanks to C. R. for inspiring (T (SUCK STREAM (CONS C L)))))) ; this routine's name. On ASCII machine A, someone opens a file FOO for input, opens a file BAR for output, and does (PRINT (SUCK FOO-STREAM '()) BAR-STREAM). They use FTP to send the file BAR over to EBCDIC machine B, run T, open BAR, and do (READ BAR-STREAM) to get the list of characters previously PRINTed. Well, this should yield the same list as if FOO were FTP'ed instead of BAR, and the call to SUCK done on machine B. Line separation may be implemented very differently on the two machines, but programs should see the same thing when they have that list of characters. This of course implies certain well-formedness restrictions on files, and assumes that FTP has a file model similar to T's (which I believe to be the case), does character set and newline translation, etc. There is of course nothing special about FTP, I only mention it to try to get a handle on the ineffable. This presentation is pretty rough but it should suggest the kind of invariant I'm after. I don't mean to annoy you by saying things you already know; just felt like writing all this down. Maybe your question was simpler, and you were just wondering which of (EQ? #\NEWLINE #\RETURN) and (EQ? #\NEWLINE #\LINEFEED) was the case; this is left undefined, and in fact the very existence of #\RETURN and #\LINEFEED is shadowy (you probably won't find them on the 370). Well, actually I don't whether that can be left undefined, because CHAR->ASCII needs to be well-defined for all characters (I think).  Date: Saturday, 7 August 1982 10:07-EDT From: Jonathan Rees To: Meehan at YALE Cc: T-Discussion at YALE Subject: newline et al From: James R. Meehan ... was there once a convention like #\CONTROL-A, #\CONTROL-B, etc.? Sounds handy. You may be thinking of Common Lisp, which supports this. T's syntax, for now at least, is #^A, #^B, etc., but I'm not sure that's "right" and besides, it doesn't work (due to bug in CONTROLIFY due to omission in code generator). Actually, come to think of it, T did support #\CONTROL-A etc. for a while. Maybe I should re-install that feature. I'm curious about what applications this would have... presumably cases where EBCDIC compatibility is not an issue (take that as a joke or not)...  Date: 7-Aug-82 5:30PM-EDT (Sat) From: James R. Meehan Subject: Re: #\control-A, etc. To: Rees at YALE Cc: T-Discussion at YALE In-Reply-To: Your message of Saturday, 7 August 1982 10:07-EDT I'm curious about what applications this would have... presumably cases where EBCDIC compatibility is not an issue (take that as a joke or not)... I was just wondering about how to write T programs that read control- characters, like a text editor, for instance, or programs that send control-sequences to erase lines, ring bells, etc. Nothing urgent. (Has there ever been a CRT that had a real, live bell inside?) -------  Date: 25-Aug-82 9:55AM-EDT (Wed) From: Natalie Dehn Subject: fexprs To: T-Discussion at YALE How does one define (in T) a function whose arguments are NOT EVAL'ED before being passed to it? -------  Date: Wednesday, 25 August 1982 12:00-EDT From: Jonathan Rees To: Dehn at YALE Cc: T-Discussion at YALE Subject: fexprs The only way to define fexpr's in T is with DEFINE-MACRO. For details see Pitman's paper "Special Forms in Lisp" in the proceedings of the 1980 Lisp Conference. E.g. (DEFINE-MACRO (DEFPROP SYMBOL VALUE INDICATOR) `(PUT ',SYMBOL ',INDICATOR ',VALUE)) (DEFINE-MACRO (OR THIS THAT) `((LAMBDA (P R) (IF P P (R))) ,THIS (LAMBDA () ,THAT))) (DEFINE-MACRO (HAIR FOO BAR . BAZ) `(HAIR-AUX ',FOO (LAMBDA () ,BAR) ,@(MAP (LAMBDA (X) `(LAMBDA () ,X)) BAZ))) In these examples, subforms which are to be used as quoted structure get QUOTE wrapped around them, forms which are to be evaluated immediately go dorectly into the expansion (like THIS, above), and forms which aren't to be evaluated immediately get (LAMBDA () ...) wrapped around them; when the value is needed the closure is called. The macro definitions themselves (NOT necessarily the forms that they produce) should be free of side-effects and unaffected by side-effects. That is, avoid calling things like PRINT and PUT. They should simply do source-to-source transformations, nothing more or less. ---- style flame follows ---- In general it is advised that one avoid fexprs/macros entirely unless there's a very good reason. ' just isn't that hard to write. Macros have questionable semantics, and their use can lead to very difficult-to-understand programs. And please, avoid using EVAL. I know of only three places where it's used correctly (READ-EVAL-PRINT-LOOP, LOAD-INTERPRETED-FILE, and CRAWL). I'm considering de-releasing it. Closures always suffice.  Date: 1-Sep-82 1:35PM-EDT (Wed) From: James R. Meehan Subject: T compatibility with UCI LISP To: T-Discussion at YALE I'm looking for recommendations on the following issue. In the process of getting people to move from UCI LISP (TLISP) to T, there are several things we can do to help. Riesbeck has already provided TLISP_TO_T, which does source-to-source transformations and goes a long way in easing the transition. But there are UCI LISP functions for which there are no T equivalents. Some of them (e.g., MODCHR) are system-dependent and must be rewritten from scratch. Others (e.g., SUBPAIR) are easy to write in T but aren't used very often. A third class of functions (e.g., PRINA, MAP) are very useful but don't have short translations in T, therefore taking them out of the jurisdiction of TLISP_TO_T. It seems reasonable to supply a "library" of "useful" T functions somehow. If they're "really useful," they should become part of T. Otherwise, we can keep them online somewhere for people to use as they please. [Perhaps there's no point in doing that. Maybe we should add everything to the system.] Many of these functions have already been written by people who have had to move large programs into T. When a function is deemed useful enough to become part of T, we face the question of whether to open-code it in the compiler. For functions that are quasi-special forms like MAPCAN, this seems appropriate; for simple, useful procedures (e.g., TCONC), there's not much the compiler can do. The quasi-special forms like MAPCAN that can be written as procedures should probably start out that way; we can change the compiler later if necessary. Specific suggestions about the MAP functions: UCI LISP has 6 MAP functions. You get your choice of returning NIL, consing, or splicing the results, and you can traverse either cars of cdrs. T has MAP, which is equivalent to MAPCAR, and WALK, which is very similar to MAPC. One option is to add library functions for the other varieties. Another choice is to allow (FOR (var ON list) ...) in addition to (FOR (var IN list) ...), thus making it a FOR-loop problem. [A problem with traversing cdrs: do you keep a separate pointer to the rest of the list, playing it safe, or do you allow the user to clobber the rest of the list? UCI LISP plays it safe.] We could also extend FOR-loops to allow INs and ONs at the same time, and add SAVE-LAST to DO, SAVE, SPLICE, and FILTER, as in UCI MLISP. Of course we can do all this with LOOP, but the goal is brevity. ------- My candidates for UCI LISP functions that are useful enough to put into T, with suitable modifications (e.g., stream parameters): NEWSYM & friends, READLIST, PRINA & friends, ERRSET, FSCNT & friends, GETDEF, UNION & friends, TCONC & LCONC, LINEREAD, NODUPLES, SORT, REPEAT, LSUBST, SUBLIS, TIMER. -------  Date: 1-Sep-82 1:53PM-EDT (Wed) From: Chris Riesbeck Subject: Re: T compatibility with UCI LISP To: T-Discussion at YALE In-Reply-To: James R. Meehan , 1-Sep-82 1:35PM-EDT (Wed) Meehan's comments seem to be a long-delayed response to Nix's original call for "what should be in T?" Specific suggestions about the MAP functions: UCI LISP has 6 MAP functions. You get your choice of returning NIL, consing, or splicing the results, and you can traverse either cars of cdrs. T has MAP, which is equivalent to MAPCAR, and WALK, which is very similar to MAPC. Actually, the last release of T implemented MAPCDR, ANYCDR, WALKCDR, and probably some others. I'm glad to see them, but the mapping forms I prefer to write in make features, such as what's returned and is it heads or tails of lists, separate syntactic markers, rather than part of a unitary name Jim's suggestion of (FOR (.. ON ..) ...) and Drew's various mapping-macros (too bizarre for me to describe) fall into my preferrred class. Also, see Jonathan's worries in an old T-Discussion about the namespace blow up with things like MEM, MEMQ, MEM?, MEMQ? ASS, ASSQ, ASS?, etc. They also could use a non-namespace wasting syntax. My candidates for UCI LISP functions that are useful enough to put into T, with suitable modifications (e.g., stream parameters): NEWSYM & friends, READLIST, PRINA & friends, ERRSET, FSCNT & friends, GETDEF, UNION & friends, TCONC & LCONC, LINEREAD, NODUPLES, SORT, REPEAT, LSUBST, SUBLIS, TIMER. TIMER is probably PIG, with additions. Is GETDEF as important when you have multiple windows and can plop something from an edit pad into a core image? I only used GETDEF to save loading a big file I had just edited. I never used it in a start-up file because it made the start-up file too dependent on not changing details in the sources (e.g., (GETDEF ... FOO) fails if a new implementation of FOO requires some subfunction in the same file -- DSKIN (or LOAD) will still work.) -------  Date: 1-Sep-82 2:21PM-EDT (Wed) From: Robert Nix Subject: Re: T compatibility with UCI LISP To: Chris Riesbeck Cc: T-Discussion at YALE In-Reply-To: Chris Riesbeck , 1-Sep-82 1:53PM-EDT (Wed) My candidates for UCI LISP functions that are useful enough to put into T, with suitable modifications (e.g., stream parameters): NEWSYM & friends, READLIST, PRINA & friends, ERRSET, FSCNT & friends, GETDEF, UNION & friends, TCONC & LCONC, LINEREAD, NODUPLES, SORT, REPEAT, LSUBST, SUBLIS, TIMER. I've implemented some packages that I've been meaning to announce, but I haven't quite gotten around to it (until now). SORT A sort package for vectors and lists. DATE a large set of machine independent routines for manipulating dates, times, and intervals. Even a date parser! I have not yet debugged this, but I wouldn't want anyone else to waste their time implementing this sort of thing. BYTERECORDS a record package for defining "record structure overlays" on top of byte vectors TERMCAPS a flexible terminal independent output package. This is intended for U, but I could make it more general. STRINGS a large set of string manipulation routines that are "missing" from T. APROPOS a teeny grep-through-the-oblist function. e.g. (apropos "fixnum") is supposed to print all of the known symbols that contain the substring "fixnum". REGULAR EXPRESSION COMPILER Compiles a regular expression notation into T code that will scan for that expression in a stream. This isn't done yet, I just want to say that I'm doing it. TABLE An undebugged implementation of associativee tables. NEXT-SUBSET A function that returns a closure that returns all of the subsets of the integers from 1..n-1 in some particular order. LCS Computes the longest common subsequence of a "set of strings" (or a list of lists of symbols, etc.) FREELISTS A small set of routines/operations for doing explicit storage management. Great for performance tuning/introducing bugs. These files are in [ED] and [ED]. Comments and suggestions are hereby solicited. -------  Date: 20-Sep-82 6:38PM-EDT (Mon) From: Drew McDermott Subject: RANDOM QUERIES To: T-Discussion at YALE Is there a way to test if a function is compiled? Is there a way to test if a symbol is defined as a macro? Is there a way to do (PROGN 'COMPILE ...)? Is there a way to SET the global value of a symbol (short of calling (shudder) EVAL)? -------  Date: 21-Sep-82 1:22PM-EDT (Tue) From: Drew McDermott Subject: random query rationale To: T-Discussion at YALE ... and another random query: How do you write BOUNDP in T? (Global value only, of course.) Rationale: I am creating a subset of ILISP, Franz, and T, so much of my code will run on any of 3 machines. It won't look like pretty T, but I am the only one likely to read it. There are good ideas in all 3 languages (believe it or not), although some of that goodness is relative to old-fashioned lisp concepts. For instance, Franz has two functions GETD and PUTD, which get the function definition from a symbol, and set it. This is a nice abstraction, since the value of a GETD in one implementation doesn't have to resemble that in another implementation in any way; it just has to be the sort of thing you can give to PUTD. GETD on a macro returns a macro definition. This is old fashioned in some ways, but so what. To have this feature in T, GETD must get the global value of a symbol, unless it's magic, when it must get the magic-val of it. Hence the need for BOUNDP. For completeness, I have a function IS-COMPILED, which distinguishes between EXPRs and SUBRs, etc. I don't think I use for it anything, but it could be valuable. Kent Pitman pointed out how nebulous this distinction is; perhaps its practical meaning is, "Test if the original source of the function is available." Oh well. IS-MACRO is much more useful. "Processors" (like the compiler or NISP's DECL macro) need to go over program text, and often do something special with macros. MACRO-EXPAND fits right in, but we need a MACRO? test, too. To implement PUTD, one needs what lisp used to call SET. And something special for the magic ones. One can use EVAL, but nice people don't do that. -------  Date: Tuesday, 21 September 1982 15:07-EDT From: Jonathan Rees To: Mcdermott at YALE Cc: T-Discussion at YALE Subject: random queries Obviously there ARE ways to do GETD and PUTD and BOUNDP and MACROP and whatever in T; the evaluator is capable of doing them, and after all, it's just a mortal T program. You should choose one of the following alternatives: (a) I could explain something internal and horrible and likely to change, which would allow you to do what you want to do inelegantly. (b) Wait 2 months or whatever for me to get things like moving the compiler and generic arithmetic out of the way and have the leisure to work on these problems. (c) Convince me that implementing BOUND? et al has higher priority than what I'm doing now. (It certainly would be more fun...) (d) Propose something and implement it yourself. Sigh. Perhaps (a) is the best.  Date: 27-Sep-82 2:22PM-EDT (Mon) From: James R. Meehan Subject: backquote & prettyprint To: T-Discussion at YALE I've been hacking at a backquote inverters, something that turn cons-, list-, and append-forms into backquote-forms. Some questions arose: (a . 'b) is the same as (a quote b). Should (a quote b) prettyprint as (a . 'b)? This came up when I was fiddling with `(a . ,b), which should prettyprint as `(a ,@b). [The current T prettyprinter doesn't do that. It prints (a **backquote-comma-marker** b). I got it to work in TLISP; I'll try T next.] `(a . ,b) evaluates b. `(a . ,@b) doesn't evaluate anything. It returns (a **backquote-atsign-marker** b). Granted, `(a . ,@b) is not exactly well-defined, but shouldn't it cause a syntax error? -------  Date: 15-Oct-82 12:42PM-EDT (Fri) From: Drew McDermott Subject: T for two To: T-Discussion at YALE, Ai-Local at YALE Some thoughts on the relationship between T, ILISP, and life are to be found in TPOLICY.TXT -------  Date: 31-Oct-82 8:37PM-EST (Sun) From: James R. Meehan Subject: Request for your collected wisdom To: T-Discussion at YALE In explaining T to various programmers, I've noticed that there are a few things in T that they find useful that aren't in the manual and don't exactly fit anywhere in particular, such as how to get "own" variables, (indeed, how to share "own" variables among several procedures), or how to use "labels" to rewrite a recursive procedure so that it's tail-recursive. Many of you have been programming in T long enough to find some of your own. If you know of similar techniques, send them to me. If there are enough, or if the ones I get seem useful enough, we may put them in the next edition of the manual. I'm not looking for horrible hacks that happen to work in this week's implementation (though you can send those, too -- I'll put them somewhere like GASP.T). Rather, I'm looking for features that would be of interest to programmers from other languages, particularly other dialects of LISP. For example, as the manual notes, MACLISP programmers (TLISP, too) sometimes write procedures as macros so that they'll compile open-coded, yet this is unadvisable in T. Why? (Presumably something to do with DEFINE-INTEGRABLE.) Mail to MEEHAN@YALE. -------  Date: 7-Nov-82 4:25PM-EST (Sun) From: James R. Meehan Subject: "Variables are usually constant"? To: Rees at YALE Cc: T-Discussion at YALE "A variable is a named place to put something. Variables are named by identifiers. This use of the term variable may often be confusing since the values of most variables never vary -- variables are usually constant." (T Manual, page 5) Could you elaborate? Do you mean that once a variable is assigned a value, it doesn't usually get a different one? This is a debatable point, but I think it's not worth going into in the manual. It's too confusing. Any objections to removing it? (Another example of "flesh out or flush") -------  Date: 8-Nov-82 5:02PM-EST (Mon) From: Drew McDermott Subject: PRETTY PRINTER To: T-Discussion at YALE Does anyone have a good one? Alternatively, could PP be made to print to the standard output? (It currently prints to the terminal.) -------  Date: Monday, 8 November 1982 21:32-EST From: Jonathan Rees To: Mcdermott at YALE Cc: T-Discussion at YALE Subject: PRETTY PRINTER (PRETTY-PRINT object stream), which should have been in the manual long ago, is hereby officially released. You can pass it whatever stream you like. If someone wants to write a reasonable pretty printer, more power to them. I have a paper about Dick Waters' pretty printer which someone might want to look at. The code for it is online somewhere. It has received high praise from some quarters. Features include: handles circular structure, PRINLEVEL and PRINLENGTH, and is user-extensible in a moderately clean way.  Date: 8-Nov-82 10:38PM-EST (Mon) From: Robert Nix Subject: I hate IF. To: T-Discussion at YALE Consider the following code: (IF (> X Y) (SET MAX X) (SET MAX Y) (FORMAT SO "Oh no, Y was bigger~&")) When does MAX get SET to Y? Who can tell. Compare it to this: (IF ((> X Y) (SET MAX X)) (T (SET MAX Y) (FORMAT SO "Oh no, Y was buffer~&"))) I hate IF because its positional syntax makes programs written with it very difficult to read, and dangerous to edit. (You probably wouldn't write the IF form above, but you might edit an existing IF into something like it.) I cringe whenever I see an IF with an else clause. Why do I use IF? I use it for pretty-printing purposes: "(COND (" advances the left margin by 7 precious spaces, while "(IF " moves it over by only 4. But, as far as I can see, this is the only thing that IF has going for it. I propose that T discard its current definition of IF, and instead adopt IF as a synonym for COND. Alternatively, how about taking a step back to FORTRAN and remove IF's ELSE clause? Make IF's syntax (IF PREDICATE &THEN-FORMS). Please don't object to this on the grounds of incompatibility with other dialects of LISP; T has made no real effort to be compatible, and besides, this is exactly the sort of incompatibility that can be handled trivially. -------  Date: Monday, 8 November 1982 23:46-EST From: Jonathan Rees To: Nix at YALE Cc: T-Discussion at YALE Subject: I hate IF. I hate the "feature" whereby IF accepts multiple alternate-forms. I would be in favor of eliminating that, and perhaps even the optionality of the alternate-forms. Thus rather than (IF pred con . alts) the syntax would be (IF pred con alt). This reverts to the original IF of the SCHEME revised report, and "fixes" some of your complaints. I don't buy the indentation argument; perhaps you should be complaining about the compiler inadequacy whereby you pay in efficiency when you introduce an auxiliary routine. Status quo does have some weight in my opinions about how T should look (viz. CAR, CONS, NIL, EQ), even though I can't really articulate where I draw the line. You may think there's a big difference between 5 and 7 characters in this case, but I don't think so. Maybe IF's presence is irrelevant and confusing; so don't use it if you think that. But even if it was flushed I don't know whether I'd rename COND to be IF.  Date: 9-Nov-82 1:28AM-EST (Tue) From: John R. Ellis Subject: Re: PRETTY PRINTER To: Rees at YALE Cc: Mcdermott at YALE, T-Discussion at YALE In-Reply-To: Jonathan Rees , Monday, 8 November 1982 21:32-EST I have a paper about Dick Waters' pretty printer which someone might want to look at. The code for it is online somewhere. [RES]GPRINT.LSP. It has received high praise from some quarters. Features include: handles circular structure, PRINLEVEL and PRINLENGTH, and is user-extensible in a moderately clean way. ELLISP users are quite happy with it as the default printer (at least the ones I've talked to). It makes a real difference having a pretty printer as the default printer. -------  Date: 9-Nov-82 1:48AM-EST (Tue) From: John R. Ellis Subject: Re: I hate IF. To: Nix at YALE Cc: T-Discussion at YALE In-Reply-To: Robert Nix , 8-Nov-82 10:38PM-EST (Mon) Nix: I hate IF because its positional syntax ... Why do I use IF? ..."(COND (" advances the left margin by 7 precious spaces, while "(IF " moves it over by only 4. Many of us ELLISP people have agreed with Bob's arguments for a long time. I know you all will barf, but maybe if I say it louder this time, you might listen: Conditional expressions are one of the most frequent expressions written. We have special symbols for arithmetic operations (less frequently used), why not conditionals? (IF (> X Y) (SET MAX X) (SET MAX Y) (FORMAT SO "Oh no, Y was bigger~&") ) or: (? ( (> X Y) (SET MAX X) ) ( T (SET MAX Y) (FORMAT SO "Oh no, Y was bigger~&") ) ) A number of us use (gasp, heaven forbid, not another unendorsed hack, and it uses KEYWORDS to boot, well not really keywords): (IF (> X Y) (THEN (SET MAX X) ) (ELSE (SET MAX Y) (FORMAT SO "Oh no, Y was bigger~&") ) ) I never have to worry about the asymmetry of IF, never have to worry about adding in yet another useless level of indentation if I want multiple expressions in one of the arms, and I find it easier to read than ? for simple code. THEN and ELSE are synonyms for PROGN. But of course, all real Lispers are required by law to barf at this, since the pretty printing doesn't match the low-level list structure (as if there were any correlation between low-level list structure and the global structure of the program that the programmer has in his head). I know, "not Lisp". Rees: Thus rather than (IF pred con . alts) the syntax would be (IF pred con alt). Sounds like a very sensible suggestion. -------  Date: 9-Nov-82 11:05AM-EST (Tue) From: James R. Meehan Subject: Composing functions of more than 1 argument To: T-Discussion at YALE A proposal: (COMPOSE a b ... z) should allow z to have any argspectrum, and that would become the argspectrum of the result. All the others (a, b, ...) are unary functions. The code is trivially different from the current version: (DEFINE (COMPOSE . PROCS) (COND ((NULL? PROCS) PROJ0) ((NULL? (CDR PROCS)) (CAR PROCS)) (T (LET ((PRELUDE (APPLY COMPOSE (CDR PROCS))) (FINALLY (CAR PROCS))) (LAMBDA arglist (FINALLY (apply PRELUDE arglist))))))) (This actually yields an argspectrum of (0 . T), but it works. Doing it "right" involves some ARGSPECTRUM hair.) -------  Date: 9-Nov-82 2:15PM-EST (Tue) From: Nathaniel Mishkin Subject: IF -- The reactionary strikes back To: T-Discussion at YALE Now I always thought that the (IF
. ) syntax was pretty awful and asymmetric. However, I've come to believe that a lot of tests are frequently asymmetric (and sometimes awful too) and that it's not such a bad idea to have an asymmetric IF. I tend to do: (IF ...) a lot. I suppose my true trogginess is calling out for: (IF (RETURN)) ... but I'm too lazy to code a CATCH at the outermost scope of the procedure I want to "return" out of. Well, enough unclean thoughts. -- Nat -------  Date: 9-Nov-82 2:46PM-EST (Tue) From: Drew McDermott Subject: Data-driven programming in T To: T-Discussion at YALE For a discussion of an actual meaningful issue, see DDT.TXT on YALE-RES. -------  Date: 9-Nov-82 2:43PM-EST (Tue) From: Drew McDermott Subject: I LOVE COND To: T-Discussion at YALE Why would anyone argue about IF when COND solved the conditional problem forever? No dangling elses, no begin-end pairs. It's perfect. The only tiny flaw is that its syntax tempts you to code something that really ought to be (COND (a (COND (b ...) (T ...))) (T (COND (b ...) (T ...)))) as (COND (a (COND (b ...) (T ...))) (b ...) (T ...) ) thus hiding the symmetry. Would that all programming constructs suffered only from flaws like this. -------  Date: 10-Nov-82 1:08AM-EST (Wed) From: James R. Meehan Subject: MEM, DEL, & Co. To: T-Discussion at YALE This is an attempt to "clean up" some of the T code that processes lists, including MEM, DEL, ASS, MAP, REVERSE, LENGTH, etc. Some of the definitions below might be useful for the manual, others for the actual implementation, others for nothing. In any case, I think it will make the LISTS chapter easier to organize; for example, it should be clearer why ANY and MAP are in the same place as MEMQ and LENGTH. Part I. Search through the tails of a list L, and stop when some predicate PRED is true of some selector SEL of the tail. Return: - the tail: (FIND->TAIL PRED SEL L) - the value of the predicate: (FIND->PRED PRED SEL L) - the position where you stopped: (FIND->POS PRED SEL L) - the selected value: (FIND->SEL PRED SEL L) (The code is in Part III. These all generalize to N lists.) -- membership -- (DEFINE (MEM PRED OBJ L) (FIND->TAIL (LAMBDA (X) (PRED OBJ X)) CAR L)) (DEFINE (MEMQ OBJ L) (MEM EQ? OBJ L)) (DEFINE (MEMBER OBJ L) (MEM ALIKEV? OBJ L)) (DEFINE MEM? (COMPOSE TRUE? MEM)) (DEFINE MEMQ? (COMPOSE TRUE? MEMQ)) (DEFINE MEMBER? (COMPOSE TRUE? MEMBER)) -- association -- (DEFINE (MEMASS PRED OBJ L) (FIND->TAIL PRED CAAR L)) [Unreleased; poor name] (DEFINE ASS (COMPOSE CAR MEMASS)) (DEFINE (ASSQ OBJ L) (ASS EQ? OBJ L)) (DEFINE (ASSOC OBJ L) (ASS ALIKEV? OBJ L)) (DEFINE MEMASS? (COMPOSE TRUE? MEMASS)) (DEFINE ASS? (COMPOSE TRUE? CAR MEMASS)) [Etc. Do we need MEMASS?, ASS?, etc.?] -- "reverse" association -- (DEFINE (RASS PRED OBJ L) (CAR (FIND->TAIL PRED CDAR L))) [Unreleased. Do we need RASSQ, RASSOC, RASSQ, etc.? Probably not.] -- ANY & EVERY -- (DEFINE (ANY PRED L) (FIND->PRED PRED CAR L)) (DEFINE (ANYCDR PRED L) (FIND->TAIL PRED ID L)) (DEFINE (SOME PRED L) (FIND->TAIL PRED CAR L)) [UCI LISP function, just for comparison] (DEFINE (EVERY PRED L) (FIND->SEL NOT (COMPOSE PRED CAR) L)) (DEFINE (EVERYCDR PRED L) (FIND->SEL NOT PRED L)) [These use the selector as a predicate. Hack.] -- position [New?] -- (DEFINE (POS PRED OBJ L) (FIND->POS (LAMBDA (X) (PRED OBJ X)) CAR L)) (DEFINE (POSQ OBJ L) (POS EQ? OBJ L)) (DEFINE (POSITION OBJ L) (POS ALIKEV? OBJ L)) -- NTHCDR & NTH -- (DEFINE (NTHCDR L INDEX) (FIND->TAIL (LAMBDA (TAIL) (IGNORE TAIL) (NEGATIVE? (DECREMENT INDEX))) L)) [How about the name NTH-TAIL instead?] (DEFINE NTH (COMPOSE CAR NTHCDR)) Part II. Go through all the tails of a list L, applying a selector to each tail, and collecting the results. (DEFINE (TRAVERSE INITIAL COLLECTOR SELECTOR) (LAMBDA (L) (DO ((L L (CDR L)) (RESULT INITIAL (COLLECTOR (SELECTOR L) RESULT))) ((NULL? L) RESULT)))) (DEFINE REVERSE (TRAVERSE '() CONS CAR)) (DEFINE LENGTH (TRAVERSE 0 + (ALWAYS 1))) (DEFINE LASTCDR (TRAVERSE '() PROJ0 ID)) [How about the name LAST-PAIR instead?] (DEFINE LAST (COMPOSE CAR LASTCDR)) [or (TRAVERSE '() PROJ0 CAR)] (DEFINE (APPEND X Y) ((TRAVERSE Y CONS CAR) X)) (DEFINE (WALK FN L) ((TRAVERSE '() IGNORE (COMPOSE FN CAR)) L) '*VALUE-OF-WALK*) [IGNORE? COMMENT?] (DEFINE (WALKCDR FN L) ((TRAVERSE '() IGNORE FN) L) '*VALUE-OF-WALKCDR*) (DEFINE (MAP FN L) (REVERSE! ((TRAVERSE '() CONS (COMPOSE FN CAR)) L))) (DEFINE (MAPCDR FN L) (REVERSE! ((TRAVERSE '() CONS FN)) L))) (DEFINE (SUBSET PRED L) (REVERSE! ((TRAVERSE '() (LAMBDA (NEW OLD) (IF (PRED OBJ NEW) (CONS NEW OLD) OLD)) CAR) L))) (DEFINE (DEL PRED OBJ L) (SUBSET (LAMBDA (X) (NOT (PRED OBJ X))) L) (DEFINE (DELQ OBJ L) (DEL EQ? OBJ L) (DEFINE (DELETE OBJ L) (DEL ALIKEV? OBJ L) Part III. Code for procedures in Part I. (DEFINE (FIND->TAIL PRED SEL L) (COND ((NULL? L) NIL) ((PRED (SEL L)) L) (ELSE (FIND->TAIL PRED SEL (CDR L))))) (DEFINE (FIND->PRED PRED SEL L) (COND ((NULL? L) NIL) ((PRED (SEL L))) (ELSE (FIND->PRED PRED SEL (CDR L))))) (DEFINE (FIND->SEL PRED SEL L) (IF L (LET ((X (SEL L))) (COND ((PRED X) X) (ELSE (FIND->SEL PRED SEL (CDR L))))))) (DEFINE (FIND->POS PRED SEL L) (DO ((L L (CDR L)) (N 0 (1+ N))) ((OR (NULL? L) (PRED (SEL L))) (IF L N)))) -------  Date: Wednesday, 10 November 1982 04:44-EST From: Jonathan Rees To: Meehan at YALE Cc: T-Discussion at YALE Subject: MEM, DEL, & Co. Looks fun. Some points: I don't understand the use of "->" at all. To me, FIND->TAIL would be a routine which takes a FIND as its argument, and coerces it somehow to be a TAIL. To give it this new meaning (and I couldn't figure out how that meaning is much different from "-") seems a very bad overloading to me. I don't see how FIND->TAIL or FIND->SEL generalize, as you say they do, to the case of N lists. Which of the N tails or values do you choose to return? These should probably become generic routines on sequences, not just lists. Thus CAR and CDR become HEAD and TAIL, etc. But this has some efficiency problems. Efficiency questions should be addressed somehow; clearly you wouldn't want to use the code you gave directly, at least not without extensively hacking the compiler. (Of course I wouldn't have expected this in your proposal; just something to think about.) I think the reason I've avoided working on this problem is that I wanted to overcome the efficiency problems first. This is similar to what I had in mind, though.  Date: 10-Nov-82 7:45AM-EST (Wed) From: James R. Meehan Subject: Re: MEM, DEL, & Co. To: Rees at YALE Cc: T-Discussion at YALE In-Reply-To: Jonathan Rees , Wednesday, 10 November 1982 04:44-EST Looks fun. Some points: I don't understand the use of "->" at all. To me, FIND->TAIL would be a routine which takes a FIND as its argument, and coerces it somehow to be a TAIL. To give it this new meaning (and I couldn't figure out how that meaning is much different from "-") seems a very bad overloading to me. All the FIND-functions search through tails. FIND->TAIL returns a tail, FIND->POS returns a position, etc. I had it as FIND-TAIL originally, but that really sounds like a direct object, as if we were looking for that. FIND-TAIL wasn't so bad, but FIND-POS, FIND-PRED, and FIND-SEL didn't sound right at all. FIND-TAIL->TAIL, FIND-TAIL->POS, etc., seem unwieldy. Dunno; I'm open to suggestions. I don't see how FIND->TAIL or FIND->SEL generalize, as you say they do, to the case of N lists. Which of the N tails or values do you choose to return? All of them. The output should be isomorphic to the input. (DEFINE (FIND->TAIL PRED SEL . LISTS) (COND ((ANY-NULL-LIST? LISTS) NIL) ;Can't use ANY, since ANY uses us. ((APPLY PRED (MAP SEL LISTS)) LISTS) (ELSE (APPLY FIND->TAIL PRED SEL (MAP CDR LISTS))))) (DEFINE (FIND->PRED PRED SEL . LISTS) (COND ((ANY-NULL-LIST? LISTS) NIL) ((APPLY PRED (MAP SEL LISTS))) (ELSE (APPLY FIND->PRED PRED SEL (MAP CDR LISTS))))) (DEFINE (FIND->POS PRED SEL . LISTS) (DO ((LISTS LISTS (MAP CDR LISTS)) (N 0 (1+ N)) (FLAG (ANY-NULL-LISTS? LISTS) (ANY-NULL-LIST? LISTS))) ((OR FLAG (APPLY PRED LISTS)) (IF FLAG NIL LISTS)))) (DEFINE (FIND->SEL PRED SEL . LISTS) (IF (ANY-NULL-LISTS? LISTS) NIL (LET ((X (MAP SEL LISTS))) (COND ((APPLY PRED X) X) (ELSE (APPLY FIND->SEL PRED SEL (MAP CDR LISTS))))))) Examples: (DEFINE (MEM PRED OBJ . LISTS) (APPLY FIND->TAIL (LAMBDA SELS (APPLY PRED OBJ SELS)) CAR LISTS)) (DEFINE (APPEND . LISTS) (COND ((NULL? LISTS) '()) ((NULL? (CDR LISTS)) (CAR LISTS)) (ELSE ((TRAVERSE (APPLY APPEND (CDR LISTS)) CONS CAR) (CAR LISTS))))) (ANY PRED SEL . LISTS) <=> (FIND->PRED PRED CAR . LISTS) (SUBSET < '(1 2 3 4 5) '(10 -11 12 -13 14)) => ((1 10) (3 12) (5 14)) These should probably become generic routines on sequences, not just lists. Thus CAR and CDR become HEAD and TAIL, etc. But this has some efficiency problems. True, but maybe it's better to describe them that way. Efficiency questions should be addressed somehow; clearly you wouldn't want to use the code you gave directly, at least not without extensively hacking the compiler. (Of course I wouldn't have expected this in your proposal; just something to think about.) Yeah, I thought that it would give the compiler fits (CONSing closures?) as well as being slow. Does the compiler curry? Does DEFINE-INTEGRABLE mean that it treats the definition as a macro so that it can optimize? The "real" implementation can cheat by not using TRAVERSE, etc. I mean, that's a lot of hair just for LENGTH. I think the reason I've avoided working on this problem is that I wanted to overcome the efficiency problems first. This is similar to what I had in mind, though. OK. Well, if you like the lexpr-versions of the FIND-functions (and if I can find the lexpr-version of TRAVERSE in my notes), how about if I put them in the LISTS chapter and say that these things are equivalent to the following definitions? The implementation can do whatever it needs until the efficiency problems get solved. The only other function I need is the modified COMPOSE (for non-unary functions); was that OK? -------  Date: 10-Nov-82 6:40PM-EST (Wed) From: James R. Meehan Subject: MEM, DEL, etc.: bugs To: Rees at YALE Cc: T-Discussion at YALE There were some errors in the code I sent you (e.g., APPEND was really APPEND-REVERSE). Just so you know I know. -------  Date: 21-Nov-82 4:15PM-EST (Sun) From: James R. Meehan Subject: On sequences To: Rees at YALE Cc: T-Discussion at YALE 1. I suggest that we define the TAIL of any empty sequence to be that empty sequence. That's currently the case for lists. (TAIL "") now yields #{a very long string whose length is -1} (cute but useless?). T 1.89 doesn't have TAIL defined for vectors. 2. Any new thoughts on what to do about generic ops on sequences (LENGTH, APPEND, MAP, WALK, MEM, COPY, ...)? If people don't want to make these names generic (I'm undecided), how about a similar set of names, using a prefix like | ("bar") in front of the old, familiar names to indicate the generic-ness? If they know the type of sequence and don't want to pay for the dispatch, they can use the original names (for lists) or long, ugly names (like VECTOR-APPEND) for other types. --- Predicates --- (|NULL? seq) (i.e., EMPTY?) (That's why it's a prefix, not a suffix) (|EQ? seq1 seq2) [same type] (|EQUIV? seq1 seq2) [not necessarily same type. E.g., '(0 1 6), '#(0 1 6), and "016" are |EQUIV?.] --- Constructors --- [These try to preserve type whenever possible.] (|MAKE-SEQUENCE length) [mixed-type] (|CONS object seq) [not necessarily the same type] (|APPEND . sequences) [not necessarily all the same type] (|APPEND! . sequences) (|COPY seq) --- Selectors --- (|CAR seq) (i.e., HEAD) [maybe should be |HEAD] settable (|CDR seq) (i.e., TAIL) [maybe should be |TAIL] settable (|NTH seq n) settable (|NTHTAIL seq n) [maybe |NTHCDR] settable (|SUBSEQ seq start count) settable (|SUBSEQ! seq start count) [shared subsequence, not defined on all types] --- Searchers --- (|MEM predicate seq) [first tail whose head satisfies predicate] (|POS predicate seq) (|ANY predicate . sequences) (|EVERY predicate . sequences) --- Traversers --- (|LENGTH seq) (|REVERSE seq) (|REVERSE! seq) (|MAP procedure . sequences) [not necessarily all the same type] (|MAP! procedure . sequences) [not necessarily all the same type] (|WALK procedure . sequences) (|FILTER predicate seq) (|FILTER! predicate seq) --- Miscellany --- (|COERCE seq type) [e.g., replacing STRING->LIST, LIST->STRING; not guaranteed to succeed, as in (|COERCE "0011020" 'BITV)] (|TYPE seq) [the MOST restrictive type, one of BIT, BYTE, CHARACTER, INTEGER, FLOAT, REAL, RATIO, NUMBER, SYMBOL, OBJECT] Perhaps with ASSERTs, the compiler could use the type-specific routine. -------  Date: 22-Nov-82 4:36PM-EST (Mon) From: Drew McDermott Subject: SEQUENCES To: T-Discussion at YALE Preliminary thoughts: 1. Despite pooh-poohing of efficiency, I consider it extremely important. Generic operations are hard to compile without a clever compiler AND declarations. I cringe at the thought of CAR doing a type dispatch that goes to the same place 99% of the time. 2. I agree with Jonathan that this should be delegated to "package hackers" for the time being. This will have the desirable effect of keeping them from grabbing the short names for sequence operations. I have never felt the slightest need for a "sequence" abstraction, and it certainly isn't going to clarify my thoughts for CAR, LENGTH, et al. to be forced to be about this new abstraction. A spiel I have delivered before: A language succeeds because of the abstractions built into it. LISP has succeeded because of lists, and T must retain this orientation. I sense that some are ashamed of these things, or feel they are old fashioned. Practice feeling proud of list structures. If someone asks what you are doing, don't say "AI research," or "Building abstractions," say, "CONSing list structure, and proud of it!" 3. Whatever is done, don't for God's sake use vertical bar to signal a generic operation. Vertical bars are used to bracket symbols with odd print names in Maclisp and its descendants. T should go along with this. (If anyone wants the relevant read macro, I have it.) -------  Date: 22-Nov-82 1:33AM-EST (Mon) From: John R. Ellis Subject: Re: On sequences To: Rees at YALE Cc: Meehan at YALE, T-Discussion at YALE In-Reply-To: Jonathan Rees , Monday, 22 November 1982 01:25-EST I'm not saying generic sequence operations are a bad idea; there are many reasons for having them. But it's extremely difficult to get right, as the Common Lisp design group will attest. I think it is only hard to get them "right" when you are constrained by efficiency requirements. Smalltalk has a very nice "generic" data structures, including sequences. -------  Date: 21-Nov-82 8:34PM-EST (Sun) From: Lewis Johnson Subject: Re: On sequences To: Meehan at YALE Cc: T-Discussion at YALE In-Reply-To: James R. Meehan , 21-Nov-82 4:15PM-EST (Sun) Perhaps at this point you should consider including |SORT in your collection of generic ops that apply to sequences. Also, I think that |SIZE would be better than |LENGTH; "length" makes sense only for sequences, but "size" is appropriate for lots of objects which are aggregrates of other objects, such as sets, bags, etc.; hence it is a better "generic" operation. Lewis -------  Date: 22-Nov-82 5:39PM-EST (Mon) From: John R. Ellis Subject: Re: SEQUENCES To: Mcdermott at YALE Cc: T-Discussion at YALE In-Reply-To: Drew McDermott , 22-Nov-82 4:36PM-EST (Mon) Despite pooh-poohing of efficiency, I consider it extremely important. Generic operations are hard to compile without a clever compiler AND declarations. I didn't mean to give the impression I was pooh-poohing efficiency when I brought up Smalltalk. On the contrary -- I was saying that generic operations were very difficult to implement well. My point was only that Common Lisp might not have come up with a very good set of generic operations precisely because efficiency was important. I have never felt the slightest need for a "sequence" abstraction, and it certainly isn't going to clarify my thoughts for CAR, LENGTH, et al. to be forced to be about this new abstraction. [This sounds like a person defending his favorite line editor against the onslaught of screen editors.] Seriously, the lack of "feeling a need" does not necessarily mean that a new idea is not worthwhile. Perhaps your lack of "need" is due to the fact that no existing efficient language has provided a decent set of generic operations. I, on the other hand, have felt a distinct need for generic operations on sequences BECAUSE I've been concerned for efficiency. How many times in Bliss, C, or Lisp have I chosen a vector to implement a sequence for efficiency, only to find out some other package used linked lists? Or vice versa? How many times have I needed to change a sequence implementation because of new constraints or because I am pick-putting some old code? How many times have I had to edit every single reference to a data structure just because I changed the sequence implementation? How many times have I gotten burned because I wanted to change the bounds of a vector, but forgot to track down every single loop that enumerated through that vector? I've done an awful lot of such editing, all in the name of efficiency. Think how much cleaner and compact your code would be if there was only one small set of primitives for accessing all the different kinds of sequences. And don't forget control structures -- just imagine if all your sequence-enumerating loops looked like (loop (for element in sequence) ... instead of (loop (incr i from 1 to array-size) (next element (array i) ) ... (loop (for element in list) ... (loop (incr i from 1 to (string-length string) ) (next char (nth-char string i) ) etc. One of the reasons that the Smalltalk system is relatively compact and elegant is because of the code-sharing resulting from well-thought-out generic operations. A trivial example is printing a sequence -- one piece of code will suffice for each different flavor of sequence. I for one am not going to dismiss the real advantages of a language like Smalltalk just because we don't have a good idea how to implement them as efficiently as we would want. Smalltalk is not perfect, but surely we can learn from other languages? We all recognize that it is a hard problem to implement generic operations well enough to be efficient compared with non-polymorphic, type-declared lanaguages (including T). And maybe now is not the time to introduce them into T. But these considerations in no way reflect on the ultimate usefulness of generic operations. A spiel I have delivered before: A language succeeds because of the abstractions built into it. LISP has succeeded because of lists, and T must retain this orientation. I sense that some are ashamed of these things, or feel they are old fashioned. Practice feeling proud of list structures. If someone asks what you are doing, don't say "AI research," or "Building abstractions," say, "CONSing list structure, and proud of it!" I don't think anyone is ashamed of consing lists in Lisp. Lisp lists are useful exactly because we don't have generic operations; Lisp lists provide a uniformly-accessed data structure that is moderately efficient for many applications. If I had to pick a single data structure, I too would pick Lisp lists. But lists are not enough (for Jacqueline Suzanne) -- witness the need for vectors in every variety of modern Lisp. Once we concede the need for different data structures, how do we best make use of them? -------  Date: Monday, 22 November 1982 01:25-EST From: Jonathan Rees To: Meehan at YALE Cc: T-Discussion at YALE Subject: On sequences 1. (TAIL "")'s behavior is a bug, but making it not be an error would violate the principle that the type-specific, open-codeable versions of generic routines should be subsets (in the mathematical sense) of the generic routines where the domain and range are restricted to the type in question. (TAIL (PROCLAIM STRING? FOO)) <=> (STRING-TAIL FOO) should hold even if FOO is ""; (STRING-TAIL "") is erroneous; therefore (TAIL "") must be erroneous. But I think TAIL should go away; see below. 2. I think that now is the wrong time to be deciding what to do about sequences. I doubt that at this early stage in the language's development we can come up with a consistent and elegant specification. The sequence chapter probably ought to be struck from the manual for the time being. People should feel free to develop their own packages and experiment, and if someone comes up with something good, the subject should be T-Discussed again. Historical footnote: One (maybe the main) reason that sequences were put into T was to support the implicit FORCE suggested by Sussman, Hanson, et al. Since in T (at least until now) forcing happens only when an operation is invoked on a delayed object, there have to be versions of CAR and CDR which are operations, so that forcing can happen when traversing delayed lists. With additional inspiration from the sequences of NIL and Common Lisp, T's notion of sequence, with generic HEAD, TAIL, etc., was born. This result is a moderately ridiculous and barely useful hack. However, I have heard that after some experience with using and implementing implicit FORCE, and teaching it to students (I think), that Sussman etc. have changed their minds, and now recommend explict FORCE. With explicit FORCE, "sequences" can go away; for the purposes of infinite lists, HEAD can be CAR and TAIL can be (FORCE (CDR ...)). This is what I intend to do with T. I haven't even heard of anyone using generic sequence operations OR delays, so I doubt these changes will be felt. I'm not saying generic sequence operations are a bad idea; there are many reasons for having them. But it's extremely difficult to get right, as the Common Lisp design group will attest.  Date: 3-Dec-82 11:28PM-EST (Fri) From: Drew McDermott Subject: Read time/compile time To: T-Discussion at YALE I have been wrestling with the T feature that all macros are expanded when a function is defined. Although my knee-jerk-stylist reflex was to see this as a straightforward way of forcing read time and compile time to be logically the same, it has proved to be such a pain that I started questioning it. The more I question, the fewer answers occur to me. I suppose the basic answer is, Things have to be this way to make the compiler run smoothly. This raises the question, How come everything used to seem smoother in the Good Old Days? To be concrete, I have some type-definition stuff whereby you can define things like this: (DEFINE TYPE-FOO -basic-definition- -patches-) (DEFINE TYPE-BAZ -basic-definition- -patches-) The patches are essentially function definitions (they provide a flexible way of defining slots -- like operations, but filling a different need). The whole point of defining types like these is so they will be known at compile time in other function definitions. When a function using slot S of type FOO (notated :(FOO S)) is compiled, all that has to be known about :(FOO S) are the names and types of the accesser and setter of :(FOO S), and the type of the contents of :(FOO S). There is no need at compile time to actually run the accesser or setter, and hence no need to expand the definition (e.g., if it is defined in another file). There is nothing preventing the patches of FOO and the patches of BAZ from referring to each other. That is :(FOO S) might be defined by a function that refers to slot :(BAZ R), and vice versa. This causes no trouble under the old regime. At interpret time the right thing obviously happens. At compile time, each function only needs to know the "external" information described before. (You do need a two-pass compiler to make sure the external information is extracted before compilation begins.) Under the new regime, the whole thing collapses, even in interpreted code. T insists on knowing about :(BAR R) while defining :(FOO S), and vice versa. So far, I have avoided the problem by rearranging files, but clearly that is not a general solution. I suppose the "official" response is that, since compiled and interpreted T are identical, I should just go to a two-pass loader of interpreted code. On the other hand, there is really no reason for things to stay the way they are. As far as I can see, adding a hack to the interpreter to delay macro-expansion until the first call would solve the problem. (Sorry -- if hacks offend you, think of it as a kind of functional call by need.) If all that seems esoteric, here is a practical consideration that everyone will appreciate: One often loads a file full of interpreted functions with the intention of running only a fraction of them. Why should you have to pay for macro-expanding all of them? An alternative is for me to define DE to interpose a level of indirection and delayed evaluation between function definition and calling. I have a feeling that this would be a mess. How do other people feel about this issue? -------  Date: Saturday, 4 December 1982 05:44-EST From: Jonathan Rees To: Mcdermott at YALE Cc: T-Discussion at YALE Subject: Load time/compile time Date: 3-Dec-82 11:28PM-EST (Fri) From: Drew McDermott To: T-Discussion I have been wrestling with the T feature that all macros are expanded when a function is defined. ... This is a real problem and I sympathize. But I'm not sure just what it is that you're doing that really requires the use of macros; why won't procedure integration do what you want? I presume that : is a readmacro; what does it expand into? Are you saying that most of the work is done at macro-expansion time, and little is done at run-time? I guess what I'm saying is that the more procedural (DEFINE) and less syntactic (DEFINE-MACRO) you make your code, the better off you are; you are supposed to be able to depend on a smart compiler to make this supposedly less efficient way of doing things work well. If it's too inefficient in INTERPRETED code, then perhaps the interpreter should be made smarter. Is it the case that you have macros which expand into BLOCKs which define both macros and procedures? This is an awkward (and some might say unclean) situation because it mixes the two semantic levels. On the other hand, there is really no reason for things to stay the way they are. As far as I can see, adding a hack to the interpreter to delay macro-expansion until the first call would solve the problem. (Sorry -- if hacks offend you, think of it as a kind of functional call by need.) I don't see how this can be done in general for compiled code. Sure, one could make the compiler do two passes over the file, but then we get still further away from some nice properties (like (COMPILE (APPEND A B)) <=> (APPEND (COMPILE A) (COMPILE B)), so to speak) that we would like the language to have; what the hell is a "file," anyhow? Why make files be part of the semantics? If all that seems esoteric, here is a practical consideration that everyone will appreciate: One often loads a file full of interpreted functions with the intention of running only a fraction of them. Why should you have to pay for macro-expanding all of them? This is completely reasonable; in fact I have been considering putting a delaying tactic into the evaluator for quite some time now, and will get around to it one day. A two-pass compiler would be a wonderful thing also, because then all sorts of optimizations are possible, not just retroactive DEFINE-INTEGRABLE's. But I certainly don't want to have anything like this in the language DEFINITION because it then becomes much harder to write semantically correct evaluators (that is, define the language's semantics). I think we've been careful so far not to "overdefine" the language; its semantics are close to being tractable. This is T's (and Scheme's) main advantage over other Lisp dialects, and one must be vigilant at every step to avoid throwing that advantage away. My opinion isn't cast in concrete; there's a lot in what you say, and it might be basically the right way to go. But it bothers me too. The way in which the system deals with macros internally is going to change a great deal in the not-too-distant future (Sussman and a few of us other Schemers are working on the semantics of macros), perhaps in such a way as to shed light on, or even force, this issue. --------- I'm sure you realize that SET is functional rather than syntactic in the sense that, e.g., (LET ((X CAR)) (SET (X Y) FOO)) sets the CAR of Y. Thus also if you compile (SET (BAZ Y) FOO) the compiler does NOT need access to BAZ's definition. This is just because (SET (BAZ Y) FOO) is equivalent to ((SETTER BAZ) Y FOO), and SETTER is a procedure (which the compiler knows a little about, the same way it knows about CAR). If BAZ isn't available then you just lose some possible optimizations, the same way as if you're missing the definition of an integrable procedure. --------- and by the way, I use the term "load-time" to refer to what you call "read-time" because it really doesn't have anything to do with what READ does.  Date: 4-Dec-82 4:36PM-EST (Sat) From: Drew McDermott Subject: More thoughts on load time/compile time To: T-Discussion at YALE (1) On a practical note, I went ahead and implemented a hack for delaying macro expansion. Basically, we define DE so that (DE sym (-args-) -body-) expands, not into (DEFINE (sym -args-) -body-) but into (DEFINE (sym -args-) (DELAY-MACROS 'sym (LIST -args-) '(LAMBDA (-args-) -body-))) DELAY-MACROS then actually defines sym, and applies it to the list of args. The new definition, with macros expanded, wipes this one out. Complications: A. This must interact properly with the data-driven programming scheme described in DDT.TXT. B. The given definition is completely unsuitable for compile time. So we must use the original scheme when it is known that the function is to be compiled. (As before, a two-pass compiler is needed.) This scheme appears to work. I will report later on how much it speeds up loading. Currently, DELAY-MACROS causes a burst of [Redefining ...] and [Assigning ...] messages. I rather appreciate these, since they tell me what's taking so long, but I'm sure there is some way to turn them off. (2) In reaction to Jonathan's remarks, e.g.: ... I'm not sure just what it is that you're doing that really requires the use of macros; why won't procedure integration do what you want? I presume that : is a readmacro; what does it expand into? Are you saying that most of the work is done at macro-expansion time, and little is done at run-time? This made me stop and think a bit, but not too much. Basically, I thought pretty hard about all these issues when I started transporting NISP to T. My thought processes have generally led me to stick with old-fashioned techniques in many cases. At first I felt bad about this, but I got over it. I am not sure what to say about the clash between T-thought and Lisp-thought. In many cases, I side with T in principle, with Lisp in practice. Again and again, old-fashioned Lisp turns out to do the right thing for the wrong reason, or no reason at all. A case in point is the layer of indirection and delay that you get from the confusion between functions and their names. Anyone can see that the people who designed things this way had no clear idea of what they were doing (one hopes), and that this is the first thing to change in a "reasonable" dialect. On the other hand, look at the inconvenience from doing things the right way! Another example is compile time vs. interpret time, and the relation of this issue to questions like whether files are to be known to Lisp. The answer on elegance grounds is clearly "no," but what a nice abstraction file transduction is for a portable Lisp dialect. Every operating system has files, for one thing. For another, it is absolutely clear when compilation is occurring and what it is operating on. Letting DE know when compilation is occurring is a relatively straightforward matter. Perhaps we need a support group (FEXPRs Anonymous?) I can turn to in moments like these to be talked back into the sobriety of Lexical Oneness. -------  Received: by YALE-BULLDOG via CHAOS; Sun, 6 Mar 83 14:41:56 EST Date: Thu, 3 Mar 83 12:46:28 EST From: Stanley Letovsky Subject: Timing T performance To: T-Discussion@YALE.ARPA, Apollo-Hackers@YALE.ARPA I want to measure the effects of certain parameter changes on the time-performance of a program. Unfortunately I work on FS1, where an unpredictable number of cycles are stolen by ring functions. Does anyone know how to write a function like TLISP's TIMER, which measures only virtual time used by the running program? -------  Received: by YALE-BULLDOG via CHAOS; Sun, 13 Mar 83 17:53:05 EST Date: Sunday, 13 March 1983 17:51-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Letovsky@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: RESET Date: Sun, 13 Mar 83 08:27:20 EST From: Stanley Letovsky Re: RESET Is there something analogous to TLISP's INITFN whereby the user can set a function which is evaluated whenever a (RESET) occurs? No. This seems like gratuitous complexity to me, although I could imagine its being useful. What particular application did you have in mind?  Received: by YALE-BULLDOG via CHAOS; Mon, 28 Mar 83 15:18:36 EST Date: Mon, 28 Mar 83 15:20:26 EST From: Chris Riesbeck Subject: read-tables To: T-Discussion@YALE.ARPA Linking read-tables to streams seems like a good idea, but I'm confused. What do I write in a file that defines a readmacro? Do I write (SET (READ-TABLE-ENTRY *THE-USER-READ-TABLE* ...) ...) or (SET *MY-READ-TABLE* (MAKE-STANDARD-READ-TABLE)) (SET (READ-TABLE-ENTRY *MY-READ-TABLE* ...) ...) or (HERALD MYFILE (READ-TABLE *MY-READ-TABLE*)) (SET (READ-TABLE-ENTRY *MY-READ-TABLE* ...) ...) or what???? In all but the first case, how does the user to get access to the readmacro being defined, by knowing about *MY-READ-TABLE*? Won't there be a need for a JOIN-READ-TABLE procedure to merge separate read-tables the way JOIN merges objects? -------  Received: by YALE-BULLDOG via CHAOS; Mon, 28 Mar 83 16:14:23 EST Date: Monday, 28 March 1983 16:14-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Riesbeck@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: read-tables From: Chris Riesbeck To: T-Discussion Linking read-tables to streams seems like a good idea, but I'm confused. What do I write in a file that defines a readmacro? Good question. (SET (READ-TABLE-ENTRY *THE-USER-READ-TABLE* ...) ...) This works, if everyone who wants the read-macro will be using *THE-USER-READ-TABLE*. This makes *THE-USER-READ-TABLE* a global resource, with its accompanying management problems. (SET *MY-READ-TABLE* (MAKE-STANDARD-READ-TABLE)) (SET (READ-TABLE-ENTRY *MY-READ-TABLE* ...) ...) This might be better. My opinion is that every major system is going to have to decide just what read syntax it wants to be using, and should do this kind of thing explicitly. Seems the user should always obtain read-macros explicitly, either by modifying his favorite read-table or by using a read-table set up by his favored total environment. (HERALD MYFILE (READ-TABLE *MY-READ-TABLE*)) (SET (READ-TABLE-ENTRY *MY-READ-TABLE* ...) ...) Notice that this might not work because the (SET ...) won't necessarily be evaluated until after the whole file is read, so the definition isn't available in the file which defines the read-macro. (Consider what happens when the file is compiled.) This will work fine as long as a fully initialized read-table already exists before anyone wants to use it; that is, if the (SET ...) isn't in the same file as the HERALD. You might try something like (HERALD MYFILE (READ-TABLE (BLOCK (DEFINE *MY-READ-TABLE* ...) (SET (READ-TABLE-ENTRY *MY-READ-TABLE* ...) ...) *MY-READ-TABLE*))) or even (HERALD MYFILE (READ-TABLE (LET ((MY-READ-TABLE ...)) (SET (READ-TABLE-ENTRY MY-READ-TABLE ...) ...) MY-READ-TABLE))) which may be considered either horrible or elegant, depending on your taste. I have no comment at this point. -------------------- If we can get all this worked out, then we'll have an environment with the marvelous property that different people can use their own favorite syntaxes for their own files, without having problems when using files written by other people. Syntax tables and locales provide parallel modularity features for managing incompatibilities on the other semantic levels. Not everyone may appreciate the hassle now, but I think the effort will pay off very big at some indefinite future point.  Received: by YALE-BULLDOG via CHAOS; Tue, 29 Mar 83 13:37:50 EST Date: Tue, 29 Mar 83 13:42:13 EST From: Jingke Li Subject: Listing procedures To: T-Discussion@YALE.ARPA Is there a procedure in T which will list all the procedures in a file? -- Jingke -------  Received: by YALE-BULLDOG via CHAOS; Mon, 28 Mar 83 16:25:15 EST Received: from YALE-BULLDOG by YALE-RES via CHAOS; Mon, 28 Mar 83 16:27:57 EST Received: from PARC-MAXC by YALE via ARPANET; Mon, 28 Mar 83 16:21:48 EST Date: 28 Mar 83 13:25 PST (Monday) From: Deutsch.PA@PARC-MAXC.ARPA Subject: Re: read-tables In-reply-to: Riesbeck@YALE.ARPA's message of Mon, 28 Mar 83 15:20:26 EST To: Chris Riesbeck cc: T-Discussion@YALE.ARPA I hope you get some clarity about this business of who knows what readtable to use. It is a bad mess in Interlisp. There are several system facilities that hold their own readtables (there are different default readtables for the editor, the read-eval-print loop, and the source code loader / compiler), and no way to get readtable settings saved with files. While linking to streams is certainly the right thing to do as far as USING the readtable goes, I don't really know how to manage the CONTENTS of the various readtables in the system. It seems to me that you can take the view that they are "global state", or you can take the view that they are associated with the files they are used to interpret / create. The latter seems to me much more likely to work out well.  Received: by YALE-BULLDOG via CHAOS; Mon, 28 Mar 83 17:34:40 EST Date: Monday, 28 March 1983 17:38-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Riesbeck@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: named lambda As you know, NAMED-LAMBDA isn't released. If it ever is, it will probably have a different syntax. It is semantically completely equivalent to the correspoinding (OBJECT (LAMBDA ...) ((IDENTIFICATION SELF) ...)), but it's implemented in a somewhat more space- (not time- !) efficient manner. You could define a macro which expands into the (OBJECT ...) form if writing it out is too verbose. Or you could DEFINE the predicate. I think LABELS will give the procedure a "name" if the code hasn't been TC'ed. (LABELS (((FOO X) ...)) FOO), yugh.  Received: by YALE-BULLDOG via CHAOS; Mon, 28 Mar 83 17:51:15 EST Date: Monday, 28 March 1983 17:55-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: T-Users-External@YALE.ARPA Subject: test message This is a test of a new mailing list, T-Users-External@Yale. If you don't want to be on this list, please let me know. The mailing list T-Users has two members: T-Users-Yale, and T-Users-External. Spread the word that VMS T is available.  Received: by YALE-BULLDOG via CHAOS; Tue, 5 Apr 83 11:40:47 EST Date: Tue, 5 Apr 83 11:38:04 EST From: Douglas Baldwin Subject: More T Graphics To: T-Users@YALE.ARPA Cc: Ellis@YALE.ARPA There is now a much more device-independent and easy to use set of graphics primitives available for T on Apollos. See file //gamma/yale/baldwin/graphics/gdev.doc for complete details. The package isn't available on VAXes yet, but this is simply because I haven't felt inspired to move it. If anyone wants it on a VAX let me know. Send bugs, comments, enhancements, etc. to me. Expect enhancements over the next few weeks. -------  Received: by YALE-BULLDOG via CHAOS; Wed, 6 Apr 83 20:55:02 EST Received: from YALE-BULLDOG by YALE-RES via CHAOS; Wed, 6 Apr 83 19:07:49 EST Received: from MIT-MC by YALE via ARPANET; Wed, 6 Apr 83 18:50:50 EST Date: 6 April 1983 18:57 EST Unauthentic-From: John D. Ramsdell From: JDR@MIT-MC.ARPA Subject: 3rd Ed of the T manual To: ramsdell @ HARV-10, t-discussion @ YALE I found the new T manual a big improvement over the last one. Specifying the resulting type of evaluation is of great help. I made a list of comments as I read the manual which I would like to give to you. 1) Something that yields an undefined value should not print any value, and functions that check their argument types should produce an error when they find the undefined value object. If this is not done, programmers will ingore the warnings and use the value of (if () 'foo) I promise you. See what our systems programmer did for AM110 scheme-in-t! 2) [p. 7] There should be a documented named-lambda or function as I have called it. Lambda with local names is useful. 3) [p. 10] Phase out the atom nil and replace it with (). In T one can always use () instead so why not evoid the confussion. Again, look at what our systems programmer did for AM110 scheme-in-t. (This will be changed). 4) [p. 16] (if pred cons alt) Is alt an implicit block? The manual suggests not, but why not? 5) [p. 28] Operations are hard to understand from the manual. I do not have any suggestions on how to fix this. 6) [p. 62] write-line is missing. 7) [p. 67] check-arg seems like a terrible way to do type checking. What happened to guard? 8) [p. 68] In gen-id, I can't figure out the type of prefix. 9) [p. 79] a) Do release bound?. Also release make-unbound so one can delete a symbol from the table. b) Stream I/O - I vote to make it more 6.001 like. In particular, make it so one can combine T functions much in the way you can combine Unix tools. I'm sure you realize how powerful this can be. I know my proposal suffers from the weird way in which one does writes. I can't think of any thing better now, so ..... c) Block I/O - I am working on this. I will give it to you when done. 10) [p. 99] Property lists as a data base?!? Ecch! I hope we can provide a better data base for T than that. I will send along a paper which gives one man's veiw on how to use a data base to store information about a Lisp program. A data base could also be used to store information on a system, e.g. a superset of the information contained in herald and require forms. Please use different words to describe property lists. John  Received: by YALE-BULLDOG via CHAOS; Thu, 7 Apr 83 13:20:36 EST Date: Thu, 7 Apr 83 13:20:37 EST From: Stanley Letovsky Subject: Interrupts To: T-Discussion@YALE.ARPA Is there provision for user programmable interrupts in T? In particular, we want to run a slave CPU asynchronously from the RS-232 port of an Apollo. -------  Received: by YALE-BULLDOG via CHAOS; Thu, 7 Apr 83 13:27:08 EST Date: Thu, 7 Apr 83 13:28:53 EST From: Nathaniel Mishkin Subject: Re: Interrupts To: Letovsky@YALE.ARPA Cc: T-Discussion@YALE.ARPA In-Reply-To: Stanley Letovsky , Thu, 7 Apr 83 13:20:37 EST Is there provision for user programmable interrupts in T? In particular, we want to run a slave CPU asynchronously from the RS-232 port of an Apollo. The Apollo system interface is not "interrupt-oriented". I.e. instead of having "software interrupts" (ala Unix and TOPS-20), it has "events". System resources (e.g. input pads, SIO lines) have "event counters" associated with them. The way you "simulate" interrupts is by waiting on a set of event counters. So if you want to be able to read from the keyboard (i.e. input pad) while waiting for an SIO event, you wait on the event counters for the input pad and the SIO line. When you unblock, the system call returns what event happened. You then process the event (e.g. read from the SIO line) and block again. This is all do-able from T. Stop by and see me if you want more information. -- Nat -------  Received: by YALE-BULLDOG via CHAOS; Tue, 12 Apr 83 15:40:17 EST Date: Tuesday, 12 April 1983 15:40-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Adams@YALE.ARPA Cc: Johnson-Lewis@YALE.ARPA, T-Users@YALE.ARPA Subject: read syntax stuff Date: Tuesday, 12 April 1983 14:56-EST From: Norman Adams To: Rees Re: read syntax stuff Why does A'B get parsed as a single atom but A(A not? I thought "(" was just a read macro, so what makes it a delimiter too? "'", and also doublequote, "#", "`", and ",", are defined with (SET (READ-TABLE-ENTRY ... #\') (LAMBDA (CH STREAM) ...)), whereas "(", and also ")" and ";", are defined with (SET (READ-TABLE-ENTRY ... #\() (NOT-CONSTITUENT (LAMBDA (CH STREAM) ...))). I don't see any reason not to release the NOT-CONSTITUENT procedure, which coerces a constituent read-macro procedure to a non-constituent one. Sure, it's a little kludgey, but so are read-macros. Another thing that should probably be released is the procedure READ-DELIMITED-SYMBOL, which implements the Maclisp/Franz/Common Lisp/Lisp Machine Lisp vertical bar symbol syntax. E.g. if (SET (READ-TABLE-ENTRY (REPL-READ-TABLE) #\|) READ-DELIMITED-SYMBOL) then "|foo|" will read as a symbol whose print name is "foo". Actually this will probably be part of a more general Maclisp/Franz reader compatibility package. Please send replies, criticisms, and suggestions to T-Discussion@Yale, not to T-Users.  Received: by YALE-BULLDOG via CHAOS; Tue, 12 Apr 83 16:28:38 EST Date: Tuesday, 12 April 1983 16:09-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: T-Users@YALE.ARPA, T-Bugs@YALE.ARPA Subject: TC & HERALD Date: Mon, 11 Apr 83 15:56:39 PST From: Dorab Patel To: rees@yale Subject: TC > (comfile "y.tab") ;Beginning T compilation on y.tab.t ** Error: attempt to call an undefined procedure (NAMELIST #{Input-stream "y.tab.t"}) >> The first form in the source file must be (HERALD filename), e.g. (HERALD Y.TAB), or else the compiler will complain that NAMELIST is unbound. I admit that the error message is cryptic; I'll fix it.  Received: by YALE-BULLDOG via CHAOS; Tue, 12 Apr 83 22:33:11 EST Date: Tue, 12 Apr 83 22:35:00 EST From: Jonathan Rees Subject: STRING->INTEGER To: Pitman@YALE.ARPA, T-DISCUSSION-TRANSCRIPT@MIT-MC.ARPA [This message failed to get through to MC when it was originally sent.] This is a hairy problem. Looking at the agony Common Lisp is going through trying to provide a general solution to this problem is enough to convince me not to address it. It has some routine which parses numbers, and it takes about ten optional arguments. What should happen if there's no number there? How does one find out at what position the parse completed? What if the number is terminated by something other than end-of-string? What about decimal points and radix prefixes? etc. I don't like installing half-solutions to complicated problems unless it really seems essential to provide the feature, and in this case it doesn't. It seems like there is some problem here but I haven't yet seen a very satisfactory solution. There is an internal system routine (STRING->INTEGER string radix) which may do the conversion you want. I'm not sure how it addresses the above problems, and of course its being unreleased means it's risky to depend on it. Maybe I can be convinced that it should be released. (Note that fixnums are an implementation hack, not really part of the language, so the manual and I avoid talking about them.) -------  Received: by YALE-BULLDOG via CHAOS; Mon, 18 Apr 83 14:53:02 EST Date: Monday, 18 April 1983 14:59-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Johnson-Lewis@YALE.ARPA Cc: T-Users@YALE.ARPA Subject: logical operations Date: Mon, 18 Apr 83 14:14:30 EST From: "W. Lewis Johnson" To: Rees Re: logical operations Are there any procedures tucked away in T for doing logical operations (bitwise AND, XOR, etc.)? As in Maclisp, Common Lisp, etc., they are called LOGAND, LOGIOR, LOGXOR, and LOGNOT. Consider these to be released. I'll put them in the next edition of the manual.  Received: by YALE-BULLDOG via CHAOS; Tue, 19 Apr 83 20:28:14 EST Received: from YALE-BULLDOG by YALE-RES via CHAOS; Tue, 19 Apr 83 20:37:33 EST Received: from MIT-MC by YALE via ARPANET; Tue, 19 Apr 83 20:21:00 EST Date: 19 April 1983 18:45 EST Unauthentic-From: John D. Ramsdell From: JDR@MIT-MC.ARPA Subject: t manual To: t-discussion @ YALE The T manual MUST have an index. I found I use the old one in preference to the new one because I can find what I am looking for! John  Received: by YALE-BULLDOG via CHAOS; Tue, 19 Apr 83 21:20:40 EST Received: from YALE-BULLDOG by YALE-RES via CHAOS; Tue, 19 Apr 83 21:29:02 EST Received: from MIT-MC by YALE via ARPANET; Tue, 19 Apr 83 21:10:15 EST Date: 19 April 1983 19:13 EST Unauthentic-From: John D. Ramsdell From: JDR@MIT-MC.ARPA Subject: Nothing is real To: t-discussion @ YALE I would like to suggest the addition of the following definition. (define *nothing* (object () ((nothing? self) t) ((print self stream) (display "" stream)))) This would be the ideal thing to return when the value of the result is unimportant. John  Received: by YALE-BULLDOG via CHAOS; Wed, 20 Apr 83 11:37:59 EST Received: from YALE-BULLDOG by YALE-RES via CHAOS; Wed, 20 Apr 83 11:46:56 EST Received: from MIT-MC by YALE via ARPANET; Wed, 20 Apr 83 11:30:10 EST Date: 20 April 1983 11:42 EST Unauthentic-From: John D. Ramsdell From: JDR@MIT-MC.ARPA Subject: floating point operation speed To: rees @ YALE, t-discussion @ YALE I received some bad information when I said that Apollo/t was slower than Apple. The correct measurement is: Apollo/Pascal 27 Sec. Apollo/T 190 Sec. Apple/Pascal 500 Sec. Thus compiled Apple code is 2-3 times slower than compiled numeric Apollo code. Maybe when Apple Pascal is compiled into native code, the program will run in about 200 Secs. Sorry about that, John  Received: by YALE-BULLDOG via CHAOS; Wed, 20 Apr 83 12:31:24 EST Date: Wednesday, 20 April 1983 12:38-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Ramsdell@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: t manual The new T manual has an index. (I think it's listed in the table of contents.) The copy you received must have been defective. I'll send you a new one.  Received: by YALE-BULLDOG via CHAOS; Wed, 20 Apr 83 12:32:08 EST Date: Wednesday, 20 April 1983 12:43-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Ramsdell@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: Nothing is real Date: 19 April 1983 19:13 EST From: JDR at MIT-MC.ARPA To: t-discussion at YALE Re: Nothing is real I would like to suggest the addition of the following definition. (define *nothing* (object () ((nothing? self) t) ((print self stream) (display "" stream)))) This would be the ideal thing to return when the value of the result is unimportant. This isn't the right way to implement objects which "don't print"; the right way is with the REPL-WONT-PRINT? operation, as documented in the manual. The object *REPL-WONT-PRINT* is probably what you're looking for.  Received: by YALE-BULLDOG via CHAOS; Wed, 20 Apr 83 12:59:54 EST Date: Wednesday, 20 April 1983 13:10-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Ramsdell@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: floating point operation speed Did you also try your benchmarks with (SET (RECKLESSNESS) 'HIGH)? This would more closely approximate what Pascal or block compilation would do.  Received: by YALE-BULLDOG via CHAOS; Thu, 21 Apr 83 16:41:56 EST Received: from YALE-BULLDOG by YALE-RES via CHAOS; Thu, 21 Apr 83 16:44:51 EST Received: from USC-ISI by YALE via ARPANET; Thu, 21 Apr 83 16:34:15 EST Date: 21 Apr 1983 1234-PST Sender: CONRAD@USC-ISI.ARPA Subject: destructive flonum operators From: ramsdell To: t-discussion@YALE There is a need for flonum operators that overwrite existing flonums. This will reduce the garbage produced by such calculations. For example, (let ((a 0.0)) (fl+! a 3.0) (fl+! a 2.3)) should have only one pointer value given to variable a during the entire execution of the let, but the value final value of a should be 5.0. John Ramsdell -------  Received: by YALE-BULLDOG via CHAOS; Thu, 21 Apr 83 16:57:31 EST Date: Thursday, 21 April 1983 17:04-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Ramsdell@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: destructive flonum operators Why not let the compiler figure this out?  Received: by YALE-BULLDOG via CHAOS; Fri, 22 Apr 83 09:11:03 EST Date: Friday, 22 April 1983 14:02-EST Unauthentic-From: F.REES at YALE-RES From: Jonathan Rees To: Day@YALE.ARPA Cc: T-Discussion@YALE.ARPA Subject: T on Twenties There are no plans as yet to do a DEC-20 T. There are many arguments both for and against such a project. At the moment it looks unlikely.  Received: by YALE-BULLDOG via CHAOS; Tue, 26 Apr 83 20:45:19 EDT Received: from YALE-BULLDOG by YALE-RES via CHAOS; Tue, 26 Apr 83 20:44:13 EDT Received: from MIT-MC by YALE via ARPANET; Tue, 26 Apr 83 20:33:24 EDT Date: 26 April 1983 20:35 EDT Unauthentic-From: John D. Ramsdell From: JDR@MIT-MC.ARPA Subject: Floating point operations. To: t-discussion @ YALE I am quite happy to hear that floating point operations will someday compile into fast code. I can understand why this is not to be done at this time. The reason it came up is that Prof. Mumford of the math department wants to do some work in object recognition which involves numeric and symbolic computations. He was quite disapointed with T. He now plannes to use Fortran; I don't know why he doesn't want to use Pascal. There is a possiblity that the numerical routines will be loaded into a process running T, so that the symbolic processing can be done in T. Who knows? The folloing results summerize our T measurements. The program used summes the integers after converting each integer to a floating point number. The best way to do this is to not use any integer arithmatic, but .... Value of limit 10000 20000 Recklessness Apple UCSD Pascal 22 44 - Apollo Pascal 4 8 - Compiled T 45 85 low Compiled T 35 63 high The T code was (define (sum-ints limit) (proclaim fixnum? limit) (do ((sum 0.0 (fl+ sum (fixnum->float count))) (count 1 (fx+ 1 count))) ; Do you proclaim sum and count ((fx> count limit) sum))) ; in the body of the do? The T code was much slower that the Apples. The apples did 32-bit arithmatic, but still. Besides the fact that floating point operations are not open coded, I found that each operation makes a new cell for the result of the operation. That is why I suggested the destructive floating point operations. As suggested by Jonathan, that is something that the compiler should do. When time permits the implementation of a optimizing numerical compiler, I look forward to seeing very interesting graphics for the Apollos running T. John PS The measurements involving fixnum operations were quite favorable. do loops turn into very fast code. I will interested in seeing how you get the factor of 2-3 speed up in new compiled code that John told me you expected.  Received: by YALE-BULLDOG via CHAOS; Fri, 29 Apr 83 10:11:12 EDT Date: Fri, 29 Apr 83 10:11:18 EDT From: John O'Donnell Subject: [Maas: The T Programming Language] To: T-Discussion@YALE.ARPA *** Forwarded Message Follows **** Received: from YALE-BULLDOG by YALE-RES via CHAOS; Fri, 29 Apr 83 07:36:46 EDT Received: from MIT-MC by YALE via ARPANET; Fri, 29 Apr 83 07:29:47 EDT Date: 29 April 1983 07:31 EDT From: Robert Elton Maas Subject: The T Programming Language To: Odonnell @ YALE cc: POURNE @ MIT-MC I wish people would stop making up one-letter names for their new programming languages, like C or T. I hope you realize that the letters C and T are trademarks of the Children's Television Workshop, after all some Sesame Street programs are brought to you by one or both of those letters!! *** End of Forwarded Message **** -------  Received: by YALE-BULLDOG via CHAOS; Fri, 29 Apr 83 13:33:59 EDT Date: Fri, 29 Apr 83 13:32:13 EDT From: Jonathan Rees Subject: [Maas: The T Programming Language] To: Odonnell@YALE.ARPA Cc: T-Discussion@YALE.ARPA, REM@MIT-MC.ARPA ... I wish people would stop making up one-letter names for their new programming languages, like C or T. ... I agree completely. I never did like the name T, but nobody ever suggested anything better. Shall we open up the discussion again? -------  Received: by YALE-BULLDOG via CHAOS; Fri, 29 Apr 83 13:35:00 EDT Date: Fri, 29 Apr 83 13:34:17 EDT From: John C Ruttenberg Subject: Re: [Maas: The T Programming Language] To: Rees@YALE.ARPA Cc: Odonnell@YALE.ARPA, T-Discussion@YALE.ARPA, REM@MIT-MC.ARPA In-Reply-To: Jonathan Rees , Fri, 29 Apr 83 13:32:13 EDT ... I wish people would stop making up one-letter names for their new programming languages, like C or T. ... I agree completely. I never did like the name T, but nobody ever suggested anything better. Shall we open up the discussion again? ------- Please no. Discussions about what to name things are hundreds of times worse than bad names. -------  Received: by YALE-BULLDOG via CHAOS; Fri, 29 Apr 83 14:06:47 EDT Date: Fri, 29 Apr 83 14:09:05 EDT From: Robert Nix Subject: Re: [Maas: The T Programming Language] To: Rees@YALE.ARPA Cc: Odonnell@YALE.ARPA, T-Discussion@YALE.ARPA, REM@MIT-MC.ARPA In-Reply-To: Jonathan Rees , Fri, 29 Apr 83 13:32:13 EDT ... I wish people would stop making up one-letter names for their new programming languages, like C or T. ... I agree completely. I never did like the name T, but nobody ever suggested anything better. Shall we open up the discussion again? I think that you should name it after your first-born son, or vice-versa. -------  Received: by YALE-BULLDOG via CHAOS; Sat, 30 Apr 83 12:29:56 EDT Received: from YALE-BULLDOG by YALE-RES via CHAOS; Sat, 30 Apr 83 10:51:10 EDT Received: from MIT-MC by YALE via ARPANET; Sat, 30 Apr 83 10:41:40 EDT Date: 30 April 1983 10:44 EDT From: Robert Elton Maas Subject: Re: [Maas: The T Programming Language] To: Nix @ YALE cc: REM @ MIT-MC, Rees @ YALE, Odonnell @ YALE Resent-Date: Sat, 30 Apr 83 12:31:50 EDT Resent-From: John O'Donnell Resent-To: T-Discussion@YALE.ARPA Date: Fri, 29 Apr 83 14:09:05 EDT From: Robert Nix I wish people would stop making up one-letter names for their new programming languages, like C or T. [quoted out of context, I also said Sesame Street programs are "brought to you by the letters ... and ..." thus all the single letters are trademarked by Children's Television Workshop; obviously I was spoofing somewhat] I agree completely. I never did like the name T, but nobody ever suggested anything better. Shall we open up the discussion again? I think that you should name it after your first-born son, or vice-versa. What do you have against daughters? After all, Ada Lovelace was the very first person to attempt to write a computer program (she didn't have a computer to run it on, so there's no way to know if she wrote a workable program or a bunch of bugs, but she did try first!). Let's use both male and female names: Female: Ada (already in use) or Andrea (android in Startrek episode), Beatrice, Corinne (nice pun with swapping memory in from disk), Dione (program used on Galileo-3 probe to Saturn and its moons), Esther (program for chemical analysis, pun) or Eve (see Adam, below), Fiona, Ginger, Heather, Imogene, June (program that got finished just at the end of fiscal year), Katy (pun, when program does something, say "katy did"), Lynette, ..., Rapunzel, ..., Zelda. Male: Adam (program on first probe to other star to establish a colony), Billy Carter (no comment), David (small system outperforms large system), Flint (Startrek character), Gomer, Horace, Ilyia (system with many nasty mis-features), Jerry (program to run medfly-killer robot), ..., Lauren (see Weinstein, below), Marvin, Nikita (Soviet software system), ..., Whit, ... Last names: Babbage, Diffie, Hellman, Knuth, Lovelace, Minsky or McCarthy, Nix, Postel, Rivest, Shannon, Von Neumann, Weinstein, ... (Let's keep this silly!!)  Received: by YALE-BULLDOG via CHAOS; Mon, 2 May 83 14:56:41 EDT Date: Mon, 2 May 83 14:55:23 EDT From: Drew McDermott Subject: Name for t To: T-Discussion@YALE.ARPA How about TEA -- T with Extended Acronym. This should generate at least as many silly puns as Franz has. E.g., the compiler could be called oolong. -------  Received: by YALE-BULLDOG via CHAOS; Tue, 3 May 83 21:33:09 EDT Received: from YALE-BULLDOG by YALE-RES via CHAOS; Tue, 3 May 83 21:31:52 EDT Received: from MIT-MC by YALE via ARPANET; Tue, 3 May 83 21:16:57 EDT Date: 3 May 1983 11:12 EDT Unauthentic-From: John D. Ramsdell From: JDR@MIT-MC.ARPA Subject: Dump labels in favor of static-locales. To: t-discussion @ YALE I would like to suggest that labels be deleted from T in favor of the idea of a static-locale. The static-locale would be exactly the same as an ordinary local except that once defined, it could never be modified as is so in an environment created by the labels statement. The syntax of the static-locale would be the same as locales so that there would be one way of defining procedures. The intent of labels and locale environments is not as different as their syntax implies. These expression are nearly the same: (locale () (define (ex-aux x c) ..... ) (lambda (a) (ex-aux a 0))) (labels ( ((ex-aux x c) ..... ) ) (lambda (x) (ex-aux a 0))) but what a difference in syntax! John  Received: by YALE-BULLDOG via CHAOS; Tue, 3 May 83 21:52:36 EDT Received: from YALE-BULLDOG by YALE-RES via CHAOS; Tue, 3 May 83 21:31:57 EDT Received: from MIT-MC by YALE via ARPANET; Tue, 3 May 83 21:17:26 EDT Date: 3 May 1983 11:28 EDT Unauthentic-From: John D. Ramsdell From: JDR@MIT-MC.ARPA Subject: Scoped syntax To: t-discussion @ YALE I seems to me that syntax additions should have scope just like function definitions do. From my understanding of the manual, define-macro works like the usual lisp macro, and works like a global function; you get it when its loaded. (Maybe I am misreading the manual). It seems to me that the following code should be equivalent: (locale () (define-integrable (a b) (- b)) (lambda (x) (a x))) (locale () (define-macro (a b) `(- ,b)) (lambda (x) (a x))) The important point is that macro or function a should be local to the locale. This implies that locales must keep syntax information; thing get hairy fast. I hope you find these suggestion helpful. John  Received: by YALE-BULLDOG via CHAOS; Tue, 3 May 83 22:42:36 EDT Date: Tue, 3 May 83 22:42:45 EDT From: "W. Lewis Johnson" Subject: Re: Scoped syntax To: T-Discussion@YALE.ARPA Cc: JDR@MIT-MC.ARPA In-Reply-To: JDR@MIT-MC.ARPA, 3 May 1983 11:28 EDT I seems to me that syntax additions should have scope just like function definitions do. Heck, it seems to me that syntax additions should have VALUES just like function definitions do. When are magical objects going to come in out of the cold, anyway? Lewis -------