perm filename COMMON.MSG[COM,LSP]15 blob sn#690808 filedate 1982-12-04 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00192 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00028 00002	 Common.1[com,lsp] is the portion of the Common Lisp file preceeding this.
C00029 00003	∂02-Oct-82  0033	MOON at SCRC-TENEX 	DEFSTRUCT options syntax 
C00032 00004	∂02-Oct-82  0928	Guy.Steele at CMU-10A 	Apalled
C00034 00005	∂02-Oct-82  0939	Guy.Steele at CMU-10A 	keyword pairs and DEFSTRUCT
C00035 00006	∂03-Oct-82  1104	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation strings
C00036 00007	∂04-Oct-82  0046	Alan Bawden <ALAN at MIT-MC> 	Documentation strings in defstruct 
C00038 00008	∂04-Oct-82  0759	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation strings in defstruct  
C00039 00009	∂04-Oct-82  1420	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	keyword pairs and OPEN    
C00046 00010	∂04-Oct-82  1642	Ginder at CMU-20C 	dlw's OPEN proposal  
C00048 00011	∂04-Oct-82  2042	Guy.Steele at CMU-10A 	Explanation of "Sesame"    
C00049 00012	∂04-Oct-82  2042	Guy.Steele at CMU-10A 	HIC lambda macros
C00050 00013	∂04-Oct-82  2047	Howard I. Cannon <HIC at MIT-MC> 	HIC lambda macros    
C00052 00014	∂04-Oct-82  2130	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	suggestions on floating point numbers and hash tables
C00057 00015	∂04-Oct-82  2138	Scott E. Fahlman <Fahlman at Cmu-20c> 	White, red, and yellow pages   
C00059 00016	∂04-Oct-82  2148	Guy.Steele at CMU-10A 	Moon's floating-point extractors proposal 
C00060 00017	∂04-Oct-82  2145	STEELE at CMU-20C 	/BALLOT/   
C00156 00018	∂05-Oct-82  0533	ZVONA at MIT-MC 	/BALLOT/
C00158 00019	∂05-Oct-82  1002	Guy.Steele at CMU-10A 	Addendum to voting procedure    
C00160 00020	∂05-Oct-82  1517	Scott E. Fahlman <Fahlman at Cmu-20c> 	/BALLOT/   
C00164 00021	∂05-Oct-82  1532	Dave Dyer       <DDYER at USC-ISIB> 	comment on lambda macros    
C00166 00022	∂05-Oct-82  1552	Earl A. Killian <EAK at MIT-MC> 	defun semantics  
C00168 00023	∂05-Oct-82  1612	Brian G. Milnes <Milnes at CMU-20C> 	/BALLOT/
C00169 00024	∂05-Oct-82  1625	Earl A. Killian <EAK at MIT-MC> 	arrays 
C00171 00025	∂05-Oct-82  1927	Alan Bawden <ALAN at MIT-MC> 	ZVONA: ~xxxxxnxxxxxxxxxxxxxxxxxxxxxx    
C00173 00026	∂05-Oct-82  2032	Masinter at PARC-MAXC 	Re: keyword pairs and OPEN 
C00176 00027	∂05-Oct-82  2317	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	arrays   
C00178 00028	∂06-Oct-82  0106	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN   
C00183 00029	∂06-Oct-82  0126	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	GLS's change to Moon's floating-point extractors proposal  
C00186 00030	∂06-Oct-82  0708	Guy.Steele at CMU-10A 	Re: defun semantics   
C00187 00031	∂06-Oct-82  0732	Guy.Steele at CMU-10A 	FLOAT-SIGN and SIGNUM 
C00189 00032	∂06-Oct-82  1112	ZVONA at MIT-MC
C00193 00033	∂06-Oct-82  1222	Dave Dyer       <DDYER at USC-ISIB> 	votes   
C00194 00034	∂06-Oct-82  1225	Kent M. Pitman <KMP at MIT-MC> 	insults 
C00197 00035	∂06-Oct-82  1423	Kent M. Pitman <KMP at MIT-MC> 	defun semantics   
C00199 00036	∂06-Oct-82  1503	MOON at SCRC-TENEX 	suggestions on floating point numbers and hash tables  
C00204 00037	∂06-Oct-82  1735	Masinter at PARC-MAXC 	Re: /BALLOT/
C00206 00038	∂06-Oct-82  1828	Scott E. Fahlman <Fahlman at Cmu-20c> 	suggestions on floating point numbers and hash tables   
C00207 00039	∂06-Oct-82  1919	Kent M. Pitman <KMP at MIT-MC> 	/BALLOT/
C00211 00040	∂06-Oct-82  2238	Guy.Steele at CMU-10A 	Documentation and error messages
C00216 00041	∂07-Oct-82  1017	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation and error messages    
C00220 00042	∂07-Oct-82  1622	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Documentation and error messages  
C00229 00043	∂07-Oct-82  1803	MIT VAX/VMS Lisp Implementors <NIL at MIT-ML> 	/BALLOT/
C00230 00044	∂07-Oct-82  1814	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation and error messages    
C00233 00045	∂07-Oct-82  1904	BROOKS at MIT-OZ at MIT-MC 	/BALLOT/    
C00234 00046	∂07-Oct-82  2221	Glenn S. Burke <GSB at MIT-ML> 	[Re: MIT VAX/VMS Lisp Implementors, Ballot]
C00236 00047	∂07-Oct-82  2351	Guy.Steele at CMU-10A 	Documentation and errors, etc.  
C00237 00048	∂08-Oct-82  1101	Skef Wholey <Wholey at CMU-20C> 	Hash tables => Hashing functions
C00238 00049	∂08-Oct-82  1111	Skef Wholey <Wholey at CMU-20C> 	Hash tables => Hashing functions
C00239 00050	∂08-Oct-82  1524	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Hash tables => Hashing functions    
C00241 00051	∂08-Oct-82  1526	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN
C00243 00052	∂08-Oct-82  1740	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: keyword pairs and OPEN  
C00250 00053	∂08-Oct-82  1800	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: keyword pairs and OPEN  
C00257 00054	∂11-Oct-82  1500	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN
C00259 00055	∂11-Oct-82  2005	MOON at SCRC-TENEX 	Re: macro expansion 
C00266 00056	∂13-Oct-82  1309	STEELE at CMU-20C 	Ballot results  
C00306 00057	∂14-Oct-82  2110	Guy.Steele at CMU-10A 	Here is a good idea, I think    
C00308 00058	∂14-Oct-82  2139	Scott E. Fahlman <Fahlman at Cmu-20c> 	Here is a good idea, I think   
C00310 00059	∂14-Oct-82  2144	Guy.Steele at CMU-10A 	Here is a terrible idea, I think
C00311 00060	∂14-Oct-82  2210	Alan Bawden <ALAN at MIT-MC> 	Here is a good idea, I think  
C00313 00061	∂14-Oct-82  2222	Alan Bawden <ALAN at MIT-MC> 	Here is a good idea, I think  
C00315 00062	∂14-Oct-82  2356	HEDRICK at RUTGERS 	A bunch of lousy ideas   
C00317 00063	∂15-Oct-82  0011	HEDRICK at RUTGERS 	A bunch of lousy ideas   
C00319 00064	∂15-Oct-82  0110	Kent M. Pitman <KMP at MIT-MC> 	conservatism in extensions  
C00321 00065	∂15-Oct-82  0152	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Here is a tired quux, I think
C00323 00066	∂15-Oct-82  1214	The Great Quux at CMU-10A 	Conservatism in extensions  
C00324 00067	∂15-Oct-82  1233	Guy.Steele at CMU-10A 	Tried Quux vindicated 
C00325 00068	∂16-Oct-82  0001	Alan Bawden <ALAN at MIT-MC> 	Overconservatism in extensions
C00327 00069	∂16-Oct-82  1055	The Great Quux at CMU-10A 	Re: Overconservatism in extensions    
C00328 00070	∂16-Oct-82  1111	The Great Quux at CMU-10A 	Re: Overconservatism in extensions    
C00329 00071	∂17-Oct-82  1255	Guy.Steele at CMU-10A 	What can I say?  
C00331 00072	∂17-Oct-82  2120	Guy.Steele at CMU-10A 	STRING-OUT, LINE-OUT and READLINE    
C00332 00073	∂17-Oct-82  2303	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	STRING-OUT -> WRITE-STRING, etc.  
C00333 00074	∂18-Oct-82  1458	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	STRING-OUT, LINE-OUT and READLINE   
C00334 00075	∂19-Oct-82  1211	George J. Carrette <GJC at MIT-ML> 
C00336 00076	∂20-Oct-82  1612	Earl A. Killian <EAK at MIT-MC> 	Proposed evaluator for Common LISP   
C00338 00077	∂20-Oct-82  1700	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: Proposed evaluator for Common LISP
C00340 00078	∂20-Oct-82  1743	Earl A. Killian <EAK at MIT-MC> 	Proposed evaluator for Common LISP   
C00341 00079	∂27-Oct-82  0010	Guy.Steele at CMU-10A 	Macros and TAGBODY tags    
C00342 00080	∂27-Oct-82  0012	Guy.Steele at CMU-10A 	SCALE-FLOAT and friends    
C00343 00081	∂27-Oct-82  0119	MOON at SCRC-TENEX 	SCALE-FLOAT and friends  
C00345 00082	∂27-Oct-82  0138	MOON at SCRC-TENEX 	Macros and TAGBODY tags  
C00346 00083	∂27-Oct-82  0141	Kent M. Pitman <KMP at MIT-MC> 	No. Don't let macros expand into prog tags.
C00349 00084	∂27-Oct-82  0704	Scott E. Fahlman <Fahlman at Cmu-20c> 	Macros and TAGBODY tags   
C00350 00085	∂04-Nov-82  1413	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Destructuring   
C00351 00086	∂06-Nov-82  1314	Scott E. Fahlman <Fahlman at Cmu-20c> 	Destructuring   
C00353 00087	∂08-Nov-82  1424	Guy.Steele at CMU-10A 	Mini-ballot 
C00356 00088	∂08-Nov-82  1524	MOON at SCRC-TENEX 	Mini-ballot    
C00358 00089	∂08-Nov-82  1659	Skef Wholey <Wholey at CMU-20C> 	Mini-ballot 
C00360 00090	∂08-Nov-82  1703	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: Mini-ballot   
C00363 00091	∂08-Nov-82  1711	Eric Benson <BENSON at UTAH-20> 	Re: Mini-ballot  
C00364 00092	∂08-Nov-82  1744	Earl A. Killian <EAK at MIT-MC> 	Mini-ballot 
C00366 00093	∂08-Nov-82  1743	ZVONA at MIT-MC 	Mini-ballot  
C00368 00094	∂08-Nov-82  1756	Scott E. Fahlman <Fahlman at Cmu-20c> 	Mini-ballot
C00370 00095	∂08-Nov-82  1803	Kent M. Pitman <KMP at MIT-MC>
C00373 00096	∂08-Nov-82  1846	MOON at SCRC-TENEX 	asterisks around variables    
C00375 00097	∂08-Nov-82  1850	MOON at SCRC-TENEX 	function specs 
C00377 00098	∂08-Nov-82  1859	MOON at SCRC-TENEX 	function specs 
C00379 00099	∂08-Nov-82  2005	Scott E. Fahlman <Fahlman at Cmu-20c> 	Revised Mini-Ballot  
C00383 00100	∂08-Nov-82  2051	Glenn S. Burke <GSB at MIT-ML> 	Mini-ballot  
C00386 00101	∂08-Nov-82  2308	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: function specs
C00390 00102	∂09-Nov-82  0000	Guy.Steele at CMU-10A 	Remarks on mini-ballot
C00393 00103	∂09-Nov-82  0055	David A. Moon <Moon at SCRC-POINTER at MIT-MC> 	Remarks on mini-ballot
C00396 00104	∂09-Nov-82  0132	Guy.Steele at CMU-10A 	Re: Remarks on mini-ballot 
C00398 00105	∂09-Nov-82  0444	Scott E. Fahlman <Fahlman at Cmu-20c> 	Remarks on mini-ballot    
C00400 00106	∂09-Nov-82  0752	ZVONA at MIT-MC 	function specs    
C00402 00107	∂09-Nov-82  0803	ZVONA at MIT-MC 	function specs    
C00404 00108	∂09-Nov-82  1423	Kent M. Pitman <KMP at MIT-MC>
C00407 00109	∂09-Nov-82  1423	Kent M. Pitman <KMP at MIT-MC> 	Mini-ballot  
C00412 00110	∂09-Nov-82  1603	Eric Benson <BENSON at UTAH-20> 	#'(LAMBDA ...) ==> CODE    
C00413 00111	∂09-Nov-82  1755	David.Dill at CMU-10A (L170DD60) 	mini-ballot
C00415 00112	∂09-Nov-82  1933	Guy.Steele at CMU-10A 	Named lambdas    
C00416 00113	∂09-Nov-82  2120	Guy.Steele at CMU-10A 	Quick query about CONSTANTP
C00418 00114	∂09-Nov-82  2234	STEELE at CMU-20C 	New proposed evaluators   
C00504 00115	∂10-Nov-82  0037	JONL at PARC-MAXC 	Re: Quick query about CONSTANTP
C00507 00116	∂10-Nov-82  0526	Scott E. Fahlman <Fahlman at Cmu-20c> 	Quick query about CONSTANTP    
C00508 00117	∂10-Nov-82  0530	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
C00510 00118	∂10-Nov-82  0751	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Named lambdas   
C00511 00119	∂10-Nov-82  0751	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: Mini-ballot 
C00519 00120	∂11-Nov-82  0725	Masinter at PARC-MAXC 	Named lambdas    
C00520 00121	∂11-Nov-82  0750	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
C00523 00122	∂11-Nov-82  0824	Masinter at PARC-MAXC 	Re: Named lambdas
C00525 00123	∂11-Nov-82  0857	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
C00528 00124	∂11-Nov-82  0943	Eric Benson <BENSON at UTAH-20> 	Re: Quick query about CONSTANTP 
C00530 00125	∂11-Nov-82  1253	Guy.Steele at CMU-CS-A 	Benson's remarks on CONSTANTP  
C00531 00126	∂11-Nov-82  1348	Earl A. Killian            <Killian at MIT-MULTICS> 	primitives  
C00535 00127	∂11-Nov-82  1349	Earl A. Killian            <Killian at MIT-MULTICS> 	primitives  
C00539 00128	∂12-Nov-82  0003	MOON at SCRC-TENEX 	Named lambdas  
C00541 00129	∂12-Nov-82  0100	MOON at SCRC-TENEX 	primitives, and dynamic binding    
C00545 00130	∂12-Nov-82  0608	Kent M. Pitman <KMP at MIT-MC> 	primitives   
C00547 00131	∂12-Nov-82  0932	Eric Benson <BENSON at UTAH-20> 	Re: primitives   
C00548 00132	∂12-Nov-82  1000	Earl A. Killian            <Killian at MIT-MULTICS> 	NAMED-LAMBDA
C00551 00133	∂12-Nov-82  1025	Earl A. Killian            <Killian at MIT-MULTICS> 	#,
C00552 00134	∂12-Nov-82  1231	MOON at SCRC-TENEX 	NAMED-LAMBDA and function cells    
C00555 00135	∂12-Nov-82  1327	Eric Benson <BENSON at UTAH-20> 	Re: NAMED-LAMBDA and function cells  
C00557 00136	∂12-Nov-82  2157	STEELE at CMU-20C 	Revised evaluators   
C00645 00137	∂13-Nov-82  0118	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	#,  
C00647 00138	∂13-Nov-82  0232	Kent M. Pitman <KMP at MIT-MC> 	#, 
C00648 00139	∂13-Nov-82  1044	JONL at PARC-MAXC 	Re: Named lambdas    
C00650 00140	∂13-Nov-82  1128	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
C00652 00141	∂13-Nov-82  1147	JONL at PARC-MAXC 	Re: Named lambdas    
C00653 00142	∂13-Nov-82  1516	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Re: Named lambdas  
C00655 00143	∂13-Nov-82  1950	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	implementing multiple values 
C00662 00144	∂13-Nov-82  2158	Kim.fateman@Berkeley 	multiple-value return  
C00666 00145	∂13-Nov-82  2207	Kim.fateman@Berkeley 	multiple-value return  
C00670 00146	∂13-Nov-82  2355	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	multiple-value return   
C00674 00147	∂14-Nov-82  0927	Martin.Griss <Griss at UTAH-20> 	Re: multiple-value return  
C00675 00148	∂14-Nov-82  1012	Kim.fateman@Berkeley 	Re:  multiple-value return  
C00678 00149	∂14-Nov-82  1314	UCBERNIE.jkf@Berkeley (John Foderaro) 	m-v on conventional machines   
C00683 00150	∂14-Nov-82  1350	Scott E. Fahlman <Fahlman at Cmu-20c> 	Multiple Values 
C00685 00151	∂14-Nov-82  1535	HEDRICK at RUTGERS 	results of analyzing answers to my question about m.v.'s    
C00699 00152	∂14-Nov-82  2207	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	implementing multiple values
C00705 00153	∂16-Nov-82  0848	Kent M. Pitman <KMP at MIT-MC> 	Multiple Value Return and Continuation Passing Style 
C00708 00154	∂16-Nov-82  0856	Kim.fateman@Berkeley 	multiple thanks   
C00710 00155	∂16-Nov-82  0859	Masinter at PARC-MAXC 	Named lambdas    
C00712 00156	∂16-Nov-82  0900	JONL at PARC-MAXC 	Multiple-Value implementations 
C00718 00157	∂16-Nov-82  0900	Masinter at PARC-MAXC 	Re: #, 
C00720 00158	∂16-Nov-82  0957	DLW at MIT-MC 	multiple-value return    
C00723 00159	∂16-Nov-82  1028	BROOKS at MIT-OZ at MIT-MC 	Re: DLW's message and Fateman's FLOOR.    
C00725 00160	∂16-Nov-82  1052	Scott E. Fahlman <Fahlman at Cmu-20c> 	DLW's message and Fateman's FLOOR.  
C00727 00161	∂16-Nov-82  1106	HEDRICK at RUTGERS 	Re: #,    
C00729 00162	∂16-Nov-82  1117	Scott E. Fahlman <Fahlman at Cmu-20c> 	DLW's message and Fateman's FLOOR.  
C00731 00163	∂16-Nov-82  1151	Guy.Steele at CMU-CS-A 	1000th message  
C00732 00164	∂16-Nov-82  1227	MOON at SCRC-TENEX 	Defining the forms to which the # constructs expand    
C00735 00165	∂16-Nov-82  1247	BROOKS at MIT-OZ at MIT-MC 	(prog1 (trunc x y))   
C00737 00166	∂16-Nov-82  1334	Alan Bawden <ALAN at MIT-MC> 	(prog1 (trunc x y)) 
C00738 00167	∂16-Nov-82  1333	Guy.Steele at CMU-CS-A 	Forcing one value from a function   
C00739 00168	∂16-Nov-82  1423	Ron <FISCHER at RUTGERS> 	Re: Obliquity of the vernacular...
C00740 00169	∂16-Nov-82  1555	Guy.Steele at CMU-CS-A 	Forcing one value from a function   
C00741 00170	∂16-Nov-82  1805	Eric Benson <BENSON at UTAH-20> 	Re: (prog1 (trunc x y))    
C00742 00171	∂16-Nov-82  1806	Masinter at PARC-MAXC 	Re: Defining the forms to which the # constructs expand  
C00745 00172	∂16-Nov-82  1817	Eric Benson <BENSON at UTAH-20> 	Re: (prog1 (trunc x y))    
C00746 00173	∂16-Nov-82  1817	Masinter at PARC-MAXC 	Re: Defining the forms to which the # constructs expand  
C00749 00174	∂16-Nov-82  1817	Glenn S. Burke <GSB at MIT-ML> 	Re: #,  
C00756 00175	∂16-Nov-82  1852	Guy.Steele at CMU-CS-A 	Masinter's remarks on #,  
C00758 00176	∂16-Nov-82  2007	MOON at SCRC-TENEX 	Re: Defining the forms to which the # constructs expand
C00760 00177	∂16-Nov-82  2113	Glenn S. Burke <GSB at MIT-ML> 	multiple values   
C00762 00178	∂17-Nov-82  0305	Masinter at PARC-MAXC 	Re: #, 
C00764 00179	∂17-Nov-82  0305	Alan Bawden <ALAN at MIT-MC> 	Defining the forms to which the # constructs expand    
C00767 00180	∂17-Nov-82  1323	JONL at PARC-MAXC 	Expansion of #, and the "residential" question.    
C00773 00181	∂17-Nov-82  1359	JONL at PARC-MAXC 	What's wrong with '#,<frob> ?  
C00778 00182	∂17-Nov-82  1541	JONL at PARC-MAXC 	What's wrong with '#,<frob> ?  
C00783 00183	∂17-Nov-82  2259	Dave Dyer       <DDYER at USC-ISIB> 	duplicate-p? 
C00784 00184	∂17-Nov-82  2316	Dave Dyer       <DDYER at USC-ISIB> 	duplicate-p? 
C00785 00185	∂18-Nov-82  0847	Masinter at PARC-MAXC 	Re: Masinter's remarks on #,    
C00787 00186	∂19-Nov-82  1904	Glenn S. Burke <GSB at MIT-ML> 	named lambdas
C00790 00187	∂19-Nov-82  1940	MOON at SCRC-TENEX 	named lambdas  
C00793 00188	∂19-Nov-82  1720	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Named lambdas   
C00796 00189	∂22-Nov-82  0156	Kent M. Pitman <KMP at MIT-MC> 	a LAMBDA special form  
C00799 00190	∂22-Nov-82  1255	Masinter at PARC-MAXC 	Re: Named lambdas
C00801 00191	∂22-Nov-82  1459	MOON at SCRC-TENEX 	Re: Named lambdas   
C00803 00192	∂22-Nov-82  1630	JONL at PARC-MAXC 	Re: Named lambdas    
C00805 ENDMK
C⊗;
;;; Common.1[com,lsp] is the portion of the Common Lisp file preceeding this.
∂02-Oct-82  0033	MOON at SCRC-TENEX 	DEFSTRUCT options syntax 
Date: Saturday, 2 October 1982  03:30-EDT
From: MOON at SCRC-TENEX
To:   Common-Lisp at SU-AI
Subject: DEFSTRUCT options syntax
In-reply-to: The message of 1 Oct 1982  08:48-EDT from Scott E. Fahlman <Fahlman at Cmu-20c>

    Date: Friday, 1 October 1982  08:48-EDT
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

    ....
    my point is just that OPEN is pretty much like the others.
Except that it is a function.

    I'm uneasy about making special forms too special, and creating forms
    that the user cannot duplicate with macros or some such.  
No one proposes to make forms that the user cannot duplicate with macros.
Indeed, I can think of no possible way to do that.

							      Perhaps we can
    extend the basic keyword mechanism to allow keyword/value, but also
    allow calling forms like (foo :key1 value1 (:key2 value2a value2b) ...)
    However, coming up with an attractive way to specify this in a macro's
    lambda-list will be pretty tough.
I assume you don't mean doing this for functions.  That would be utterly wrong.

We could easily add another & word to DEFMACRO if we decide it is desirable
to have an even more trivial way to accept such syntax in macros than the
straightforward way of looping over the form checking LISTP and CAR.

∂02-Oct-82  0928	Guy.Steele at CMU-10A 	Apalled
Date:  2 October 1982 1229-EDT (Saturday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Apalled

A marvelous word, this.  Perhaps KMP meant that Common LISP is in
danger of being "APPLEd", that is, forced into the Procrustean bed
of an APPLE's memory size.  This danger can be avoided by making the
language so large that it cannot possiblt be shoehorned into an APPLE.
However, I think this is already the case without RESTART being
added.
Or perhaps Common LISP is being "APL'd", but better to blame that on
REDUCE and MAP than on RESTART.
But most likely is that he simply wished to "applaud" the RESTART form.

(Sorry, KMP, don't mean to tease, but it's wonderful how this typo
landed splat between four or five applicable words.)
--Quux

∂02-Oct-82  0939	Guy.Steele at CMU-10A 	keyword pairs and DEFSTRUCT
Date:  2 October 1982 1240-EDT (Saturday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: keyword pairs and DEFSTRUCT

I am in sympathy with leaving DEFSTRUCT as is.  Indeed, there may be
something odd about DEF-forms.  OPEN was the biggest thorn, to my mind.

∂03-Oct-82  1104	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation strings
Date: Sunday, 3 October 1982  14:03-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: Documentation strings


Gary Brown noticed that DEFMACRO and DEFSTRUCT are not documented as
taking documentation strings.  DEFMACRO certainly should, since its form
parallels that of DEFUN, and adding this to DEFSTRUCT seems to be a good
idea as well.  Any problems with this?

-- Scott

∂04-Oct-82  0046	Alan Bawden <ALAN at MIT-MC> 	Documentation strings in defstruct 
Date: 4 October 1982 03:45-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Documentation strings in defstruct
To: common-lisp at SU-AI

    Date: Sunday, 3 October 1982  14:03-EDT
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

    Gary Brown noticed that DEFMACRO and DEFSTRUCT are not documented as
    taking documentation strings.  DEFMACRO certainly should, since its form
    parallels that of DEFUN, and adding this to DEFSTRUCT seems to be a good
    idea as well.  Any problems with this?

How about:

(defstruct (spaceman (:include person)
		     (:documentation "A spaceman.
The definition of a spaceman includes the definition of a person.
Additionally a spaceman has a helmit-size and a favorite-beverage.
The default favorite-beverage is Tang (tm)."))
  helmet-size
  (favorite-beverage 'tang))

∂04-Oct-82  0759	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation strings in defstruct  
Date: Monday, 4 October 1982  10:49-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Alan Bawden <ALAN at MIT-MC>
Cc:   common-lisp at SU-AI
Subject: Documentation strings in defstruct


The use of a :DOCUMENTATION keyword in DEFSTRUCT looks OK, modulo the
auto-fill issues discussed earlier.

-- Scott

∂04-Oct-82  1420	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	keyword pairs and OPEN    
Date: Monday, 4 October 1982, 17:08-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: keyword pairs and OPEN
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-reply-to: The message of 2 Oct 82 12:40-EDT from Guy.Steele at CMU-10A

Speaking of OPEN being the biggest thorn, I owe you a proposal.  Here it
is.

OPEN takes a filename as its first argument.  The rest of its arguments
are keyword/value pairs.

WITH-OPEN-STREAM's first subform is a list of a variable (to be bound to
a stream), a filename, and the rest of the elements are keyword/value
pairs.

The keywords are as follows, with their possible values and defaults:

:DIRECTION	:INPUT (the default), :OUTPUT, :APPEND, :OVERWRITE, :PROBE
	:INPUT - The file is expected to exist.  Output operations are not allowed.
	:OUTPUT - The file is expected to not exist.  A new file is created.  Input
			operations are not allowed.
	:APPEND - The file is expected to exist.  Input operations are not allowed.
			New characters are appened to the end of the existing file.
	:OVERWRITE - The file is expected to exist.  All operations are allowed.
			The "file pointer" starts at the beginning of the file.
	:PROBE - The file may or may not exist.  Neither input nor output operations
			are allowed.  Furthermore, it is not necessary to close the stream.

:CHARACTERS	T (the default), NIL, :DEFAULT
	T - Open the file for reading/writing of characters.
	NIL - Open the file for reading/writing of bytes (non-negative integers).
	:DEFAULT - Let the file system decide, based on the file it finds.

:BYTE-SIZE	a fixnum or :DEFAULT (the default)
	a fixnum - Use this byte size.
	:DEFAULT - Let the file system decide, based on the file it finds.

:IF-EXISTS	:ERROR (the default), :NEW-VERSION, :RENAME,
		:RENAME-AND-DELETE, :OVERWRITE, :APPEND, :REPLACE
	Ignored if direction is not :OUTPUT.  This tells what to do if the file
	that you're trying to create already exists.
	:ERROR - Signal an error.
	:NEW-VERSION - Create a file with the same filename except with "latest" version.
	:RENAME - Rename the existing file to something else and proceed.
	:RENAME-AND-DELETE - Rename the existing file and delete (but don't expunge,
		if your system has undeletion) it, and proceed.
	:OVERWRITE - Open for :OVERWRITE instead.  (If your file system doesn't have
		this, use :RENAME-AND-DELETE if you have undeletion and :RENAME otherwise.)
	:APPEND - Open for :APPEND instead.
	:REPLACE - Replace the existing file, deleting it when the stream is closed.

:IF-DOES-NOT-EXIST	:ERROR (the default), :CREATE
	Ignored if direction is neither :APPEND nor :OVERWRITE
	:ERROR - Signal an error.
	:CREATE - Create the file and proceed.


Notes:

I renamed :READ-ALTER to :OVERWRITE; :READ-WRITE might also be good.

The :DEFAULT values are very useful, although some systems cannot figure
out this information.  :CHARACTERS :DEFAULT is especially useful for
LOAD.  Having the byte size come from the file only when the option is
missing, as the latest Common Lisp manual says, is undesirable because
it makes things harder for programs that are passing the value of that
keyword argument as computed from an expression.

Example of OPEN:
     (OPEN "f:>dlw>lispm.init" :DIRECTION :OUTPUT)

Example of WITH-OPEN-FILE:
     (WITH-OPEN-FILE (STREAM "f:>dlw>lispm.init" :DIRECTION :OUTPUT) ...)

OPEN can be kept Maclisp compatible by recognizing whether the second
argument is a list or not.  Lisp Machine Lisp does this for the benefit
of old programs.  The new syntax cannot be mistaken for the old one.

I removed :ECHO because we got rid of MAKE-ECHO-STREAM at the last
meeting.

Other options that the Lisp Machine will probably have, and which might
be candidates for Common Lisp, are: :INHIBIT-LINKS, :DELETED,
:PRESERVE-DATES, and :ESTIMATED-SIZE.

∂04-Oct-82  1642	Ginder at CMU-20C 	dlw's OPEN proposal  
Date:  4 Oct 1982 1940-EDT
From: Ginder at CMU-20C
Subject: dlw's OPEN proposal
To: steele at CMU-20C
cc: common-lisp at SU-AI

The :APPEND keyword may be misleading in conjuction with Sesame's
"write once" files.  I suppose you could copy the contents of the
:APPEND'ed file into a new one and start from there and consider this
an implementation detail.  Where would stuff like this be explained in
the manual?  Where would the LM people's extensions be explained?  I
realize that these explanations are to be in the "red pages", but does
that mean that I have to look up both the white pages and red pages
documentation for a system fun?  What if it's also extended in the
yellow pages?  Will red and yellow pages be inserted into the middle
of the white pages at "appropriate" places?  Pointers to them?  
-Joe
-------

∂04-Oct-82  2042	Guy.Steele at CMU-10A 	Explanation of "Sesame"    
Date:  4 October 1982 2250-EDT (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Explanation of "Sesame"

Sesame is the Spice file system, to which Spice LISP must eventually
interface.  If we are lucky, they'll let us tell them what we need.

∂04-Oct-82  2042	Guy.Steele at CMU-10A 	HIC lambda macros
Date:  4 October 1982 2341-EDT (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: HIC lambda macros

I have a question about the proposed lambda macros: do they occupy the
function name space, or a separate name space?  That is, can I have
a lambda macro and also an ordinary macro with the same name?  Or
a function and a lambda-macro with the same name?

∂04-Oct-82  2047	Howard I. Cannon <HIC at MIT-MC> 	HIC lambda macros    
Date: 4 October 1982 23:46-EDT
From: Howard I. Cannon <HIC at MIT-MC>
Subject:  HIC lambda macros
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI

    Date: 4 October 1982 2341-EDT (Monday)
    From: Guy.Steele at CMU-10A
    To:   common-lisp at SU-AI
    Re:   HIC lambda macros

    I have a question about the proposed lambda macros: do they occupy the
    function name space, or a separate name space?  That is, can I have
    a lambda macro and also an ordinary macro with the same name?  Or
    a function and a lambda-macro with the same name?

They occupy a different namespace.  On the Lisp Machine, lambda macros
reside on the LAMBDA-MACRO property of their name.  However, there is
a function-spec to reference them by, so you don't need to know this.

∂04-Oct-82  2130	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	suggestions on floating point numbers and hash tables
Date:  5 Oct 1982 0030-EDT
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: suggestions on floating point numbers and hash tables
To: common-lisp at SU-AI

We have just finished most of the code needed to support Common Lisp
numbers, and are working on hash tables.  In the process, we have
noticed a few things:

When you see 1.0, it is hard to know what the precision is. We would
like to make sure that if you write something out and read it back in,
it is EQUAL to what you started with.  Thus you should consider doing
one of the following:

  - adopt a convention where you can tell the precision based on the
	number of digits printed.  E.g. 1.00000 would be single, but
	1.000000000000000 would be double.  If you follow such a
	convention in both READ and PRINT, it should be possible to
	preserve the type.  (This would replace the
	READ-DEFAULT-FLOAT-FORMAT flag.) This has the advantage of being
	to some extent machine-independent, in that 1.0000 might be
	single-precision on the VAX and short on the DEC-20.

  - always print an exponent marker, or maybe always print it when the
	it is not the same as READ-DEFAULT-FLOAT-FORMAT.

(At the moment, we are always supplying an exponent marker when it is
different from the default.)

We do not notice any way to write out hash tables.  We suggest that you
adopt a # syntax for that.  In my opinion, it should be possible to
write out and read back in as many kinds of user data structures as is
possible.

You specify a default packing factor of .8 for hash tables. I wonder
whether you really want this number to be defined in the manual. It
seems to me that the best packing factor may well be
implementation-dependent, because it will depend upon the way the
implementors have taken certain space-time tradeoffs. For various
reasons we are looking at using a algorithm where resolving clashes will
be fairly expensive.  Thus we intend to use a much lower default packing
factor.  (The method involved would use less storage space per item, so
we could afford the larger tables implied.)  

Finally, we wonder whether having separate MAKE-xxx-HASH-TABLE functions
but the same PUT-HASH and GET-HASH for all types is the right way to go.
At least in our implementation, the structure of all hash tables is
identical.  What is different among the tables is how you compare
entries.  We think it would make more sense to have one MAKE-HASH-TABLE
and separate access functions.  Since the user supplies to hash table
type when he creates it, we just have to save it somewhere in the table,
and then use it behind his back to change the meaning of the access
functions.  Although I don't quite know how one would use it, in
principle it would make sense to put different kinds of items into the
same hash table using different functions, something that is ruled out
by your proposal.  Also, if there were only one kind of hash table, it
would be slightly easier to PRINT and READ them.

-------

∂04-Oct-82  2138	Scott E. Fahlman <Fahlman at Cmu-20c> 	White, red, and yellow pages   
Date: Tuesday, 5 October 1982  00:37-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Ginder at CMU-20C
Cc:   common-lisp at SU-AI
Subject: White, red, and yellow pages


There are a number of operating systems that will not be able to support
:APPEND to files.  Where it is clear that there will be some differences
between implementations, the white pages should mention this: "Note: not
all implementations will be able to support :APPEND."  Or some such.

In general, it is impossible for the white pages to flag all extensions
made by all current and future Common Lisp implementations, so you will
indeed have to be familiar with the red pages for your implementation.
Most of the extensions will be easy to remember, or will be things you
never want to use anyway; for the others, an obvious techniques is to
mark the passage in the white pages that are modified in the red.
I assume that Zetalisp will continue to have a separate manual, so their
very extensive supersetting will not be a problem.

-- Scott

∂04-Oct-82  2148	Guy.Steele at CMU-10A 	Moon's floating-point extractors proposal 
Date:  4 October 1982 2355-EDT (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Moon's floating-point extractors proposal

I support Moon's proposal, but would like to suggest that FLOAT-SIGN
be modified to
	(FLOAT-SIGN x &optional (y (float 1 x)))
	returns z such that x and z have same sign and (= (abs y) (abs z)).
In this way (FLOAT-SIGN x) returns 1.0 or -1.0 of the same format as x,
and FLOAT-SIGN of two arguments is what the IEEE proposal calls COPYSIGN,
a useful function indeed in numerical code.
--Guy

∂04-Oct-82  2145	STEELE at CMU-20C 	/BALLOT/   
Date:  5 Oct 1982 0041-EDT
From: STEELE at CMU-20C
Subject: /BALLOT/
To: common-lisp at SU-AI
cc: b.steele at CMU-10A

?????????????????????????????????????????????????????????????????????????????
?  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  ?
?  %  =================================================================  %  ?
?  %  =  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  =  %  ?
?  %  =  $  +++++++++++++++++++++++++++++++++++++++++++++++++++++  $  =  %  ?
?  %  =  $  +  ###############################################  +  $  =  %  ?
?  %  =  $  +  #  /////////////////////////////////////////  #  +  $  =  %  ?
?  %  =  $  +  #  /  The October 1982 Common LISP Ballot  /  #  +  $  =  %  ?
?  %  =  $  +  #  /////////////////////////////////////////  #  +  $  =  %  ?
?  %  =  $  +  ###############################################  +  $  =  %  ?
?  %  =  $  +++++++++++++++++++++++++++++++++++++++++++++++++++++  $  =  %  ?
?  %  =  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  =  %  ?
?  %  =================================================================  %  ?
?  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  ?
?????????????????????????????????????????????????????????????????????????????

Here is what you have all been waiting for!  I need an indication of
consensus or lack thereof on the issues that have been discussed by
network mail since the August 1982 meeting, particularly on those issues
that were deferred for proposal for which proposals have now been made.

There are 28 questions, each requiring only a one-letter answer.  As always,
if you don't like any of the choices, answer "x".  To make my life easier
by permitting mechanical collation of responses, please respond as follows:
	(a) send a reply message to Guy.Steele @ CMU-10A.
	(b) *PLEASE* be sure the string "/BALLOT/" is in the subject line,
	    as it is in this message (the double quotes, not the slashes,
	    are metasyntactic!).
	(c) The very first non-blank line of your message should have
	    exactly 29 non-blank characters on it.  The first should be a
	    tilde ("~") and the rest should be your votes.
	    You may put spaces between the letters to improve readability.
	(d) Following the first non-blank line, place any remarks about
	    issues on which you voted "x".
Thank you for your help.  I would appreciate response by Friday, October 8.
--Guy

1.  How shall the case for a floating-point exponent specifier
output by PRINT and FORMAT be determined?
	(a) upper case, for example 3.5E6
	(b) lower case, for example 3.5e6
	(c) a switch
	(d) implementation-dependent

2.  Shall we change the name SETF to be SET?   (y) yes   (n) no

3.  Shall there be a type specifier QUOTE, such that (QUOTE x) = (MEMBER x)?
Then MEMBER can be eliminated; (MEMBER x y z) = (OR 'x 'y 'z).  Also one can
write such things as (OR INTEGER 'FOO) instead of (OR INTEGER (MEMBER FOO)).
	(y) yes   (n) no

4.  Shall MOON's proposal for LOAD keywords, revised as shown below, be used?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Wednesday, 25 August 1982, 14:01-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
	[slightly revised]
Here is a revised proposal:

Keyword		Default		Meaning

:PACKAGE	NIL		NIL means use file's native package, non-NIL
				is a package or name of package to load into.

:VERBOSE	*LOAD-VERBOSE*	T means print a message saying what file is
				being loaded into which package.

:PRINT		NIL		T means print values of forms as they are evaluated.

:ERROR		T		T means handle errors normally; NIL means that
				a file-not-found error should return NIL
				rather than signalling an error.  LOAD returns
				the pathname (or truename??) of the file it
				loaded otherwise.

:SET-DEFAULT-PATHNAME	*LOAD-SET-DEFAULT-PATHNAME*
				T means update the pathname default
				for LOAD from the argument, NIL means don't.

:STREAM		NIL		Non-NIL means this is an open stream to be
				loaded from.  (In the Lisp machine, the
				:CHARACTERS message to the stream is used to
				determine whether it contains text or binary.)
				The pathname argument is presumed to be associated
				with the stream, in systems where that information
				is needed.

The global variables' default values are implementation dependent, according
to local conventions, and may be set by particular users according to their
personal taste.

I left out keywords to allow using a different set of defaults from the normal
one and to allow explicit control over whether a text file or a binary file
is being loaded, since these don't really seem necessary.  If we put them in,
the consistent names would be :DEFAULT-PATHNAME, :CHARACTERS, and :BINARY.
----------------------------------------------------------------

5.  Shall closures over dynamic variables be removed from Common LISP?
	(y) yes   (n) no

6.  Shall LOOP, as summarized below, be included in Common LISP?
	(y) yes   (n) no
----------------------------------------------------------------
Date: 26 August 1982 18:51-EDT
From: David A. Moon <MOON at MIT-MC>

Here is an extremely brief summary of the proposed new LOOP design, which
has not yet been finalized.  Consult the writeup on LOOP in the Lisp
Machine manual or MIT LCS TM-169 for background information.  Constructive
comments are very welcome, but please reply to BUG-LOOP at MIT-ML, not to
me personally.

(LOOP form form...) repeatedly evaluates the forms.

In general the body of a loop consists of a series of clauses.  Each
clause is either: a series of one or more lists, which are forms to be
evaluated for effect, delimited by a symbol or the end of the loop; or
a clause-introducing symbol followed by idiosyncratic syntax for that
kind of clause.  Symbols are compared with SAMEPNAMEP.  Atoms other than
symbols are in error, except where a clause's idiosyncratic syntax permits.

1. Primary clauses

1.1 Iteration driving clauses

These clauses run a local variable through a series of values and/or
generate a test for when the iteration is complete.

REPEAT <count>
FOR/AS <var> ...
CYCLE <var> ...

  I won't go into the full syntax here.  Features include: setting
  to values before starting/on the first iteration/on iterations after
  the first; iterating through list elements/conses; iterating through
  sequence elements, forwards or backwards, with or without sequence-type
  declaration; iterating through arithmetic progressions.  CYCLE reverts
  to the beginning of the series when it runs out instead of terminating
  the iteration.

  It is also possible to control whether or not an end-test is generated
  and whether there is a special epilogue only evaluated when an individual
  end-test is triggered.

1.2 Prologue and Epilogue

INITIALLY form form...		forms to be evaluated before starting, but
				after binding local variables.
FINALLY form form...		forms to be evaluated after finishing.

1.3 Delimiter

DO	a sort of semicolon needed in odd situations to terminate a clause,
	for example between an INITIALLY clause and body forms when no named
	clause (e.g. an iteration-driving clause) intervenes.
	We prefer this over parenthesization of clauses because of the
	general philosophy that it is more important to make the simple cases
	as readable as possible than to make micro-improvements in the
	complicated cases.

1.4 Blockname

NAMED name		Gives the block generated by LOOP a name so that
			RETURN-FROM may be used.

This will be changed to conform with whatever is put into Common Lisp
for named PROGs and DOs, if necessary.

2. Relevant special forms

The following special forms are useful inside the body of a LOOP.  Note
that they need not appear at top level, but may be nested inside other
Lisp forms, most usefully bindings and conditionals.

(COLLECT <value> [USING <collection-mode>] [INTO <var>] [BACKWARDS]
		[FROM <initial-value>] [IF-NONE <expr>] [[TYPE] <type>])
This special form signals an error if not used lexically inside a LOOP.
Each time it is evaluated, <value> is evaluated and accumulated in a way
controlled by <collection-mode>; the default is to form an ordered list.
The accumulated values are returned from the LOOP if it is finished
normally, unless INTO is used to put them into a variable (which gets
bound locally to the LOOP).  Certain accumulation modes (boolean AND and
OR) cause immediate termination of the LOOP as soon as the result is known,
when not collecting into a variable.

Collection modes are extensible by the user.  A brief summary of predefined
ones includes aggregated boolean tests; lists (both element-by-element and
segment-by-segment); commutative/associative arithmetic operators (plus,
times, max, min, gcd, lcm, count); sets (union, intersection, adjoin);
forming a sequence (array, string).

Multiple COLLECT forms may appear in a single loop; they are checked for
compatibility (the return value cannot both be a list of values and a
sum of numbers, for example).

(RETURN value) returns immediately from a LOOP, as from any other block.
RETURN-FROM works too, of course.

(LOOP-FINISH) terminates the LOOP, executing the epilogue and returning
any value defined by a COLLECT special form.

[Should RESTART be interfaced to LOOP, or only be legal for plain blocks?]

3. Secondary clauses

These clauses are useful abbreviations for things that can also be done
using the primary clauses and Lisp special forms.  They exist to make
simple cases more readable.  As a matter of style, their use is strongly
discouraged in complex cases, especially those involving complex or
nested conditionals.

3.1 End tests

WHILE <expr>		(IF (NOT <expr>) (LOOP-FINISH))
UNTIL <expr>		(IF <expr> (LOOP-FINISH))

3.2 Conditionals

WHEN <expr> <clause>	The clause is performed conditionally.
IF <expr> <clause>	synonymous with WHEN
UNLESS <expr> <clause>	opposite of WHEN

AND <clause>		May be suffixed to a conditional.  These two
ELSE <clause>		might be flushed as over-complex.

3.3 Bindings

WITH <var> ...		Equivalent to wrapping LET around the LOOP.
			This exists to promote readability by decreasing
			indentation.

3.4 Return values

RETURN <expr>		synonymous with (RETURN <expr>)

COLLECT ...		synonymous with (COLLECT ...)
NCONC ...		synonymous with (COLLECT ... USING NCONC)
APPEND, SUM, COUNT, MINIMIZE, etc. are analogous
ALWAYS, NEVER, THEREIS	abbreviations for boolean collection

4. Extensibility

There are ways for users to define new iteration driving clauses which
I will not go into here.  The syntax is more flexible than the existing
path mechanism.

There are also ways to define new kinds of collection.

5. Compatibility

The second generation LOOP will accept most first-generation LOOP forms
and execute them in the same way, although this was not a primary goal.
Some complex (and unreadable!) forms will not execute the same way or
will be errors.

6. Documentation

We intend to come up with much better examples.  Examples are very
important for developing a sense of style, which is really what LOOP
is all about.
----------------------------------------------------------------

7.  Regardless of the outcome of the previous question, shall CYCLE
be retained and be renamed LOOP, with the understanding that statements
of the construct must be non-atomic, and atoms as "statements" are
reserved for extensions, and any such extensions must be compatible
with the basic mening as a pure iteration construct?
	(y) yes   (n) no

8.  Shall ARRAY-DIMENSION be changed by exchanging its arguments,
to have the array first and the axis number second, to parallel
other indexing operations?
	(y) yes   (n) no

9.  Shall MACROEXPAND, as described below, replace the current definition?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Sunday, 29 August 1982, 21:26-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>

Here is my promised proposal, with some help from Alan.

MACRO-P becomes a predicate rather than a pseudo-predicate.
Everything on pages 92-93 (29July82) is flushed.

Everything, including the compiler, expands macros by calling MACROEXPAND
or MACROEXPAND-1.  A variable, *MACROEXPAND-HOOK*, is provided to allow
implementation of displacing, memoization, etc.

The easiest way to show the details of the proposal is as code.  I'll try to
make it exemplary.

(DEFVAR *MACROEXPAND-HOOK* 'FUNCALL)

(DEFUN MACROEXPAND (FORM &AUX CHANGED)
  "Keep expanding the form until it is not a macro-invocation"
  (LOOP (MULTIPLE-VALUE (FORM CHANGED) (MACROEXPAND-1 FORM))
	(IF (NOT CHANGED) (RETURN FORM))))

(DEFUN MACROEXPAND-1 (FORM)
  "If the form is a macro-invocation, return the expanded form and T.
  This is the only function that is allowed to call macro expander functions.
  *MACROEXPAND-HOOK* is used to allow memoization."
  (DECLARE (VALUES FORM CHANGED-FLAG))

  (COND ((AND (PAIRP FORM) (SYMBOLP (CAR FORM)) (MACRO-P (CAR FORM)))
	 (LET ((EXPANDER (---get expander function--- (CAR FORM))))
	   ---check for wrong number of arguments---
	   (VALUES (FUNCALL *MACROEXPAND-HOOK* EXPANDER FORM) T)))
	(T FORM)))

;You can set *MACROEXPAND-HOOK* to this to get traditional displacing
(DEFUN DISPLACING-MACROEXPAND-HOOK (EXPANDER FORM)
  (LET ((NEW-FORM (FUNCALL EXPANDER FORM)))
    (IF (ATOM NEW-FORM)
	(SETQ NEW-FORM `(PROGN ,NEW-FORM)))
    (RPLACA FORM (CAR NEW-FORM))
    (RPLACD FORM (CDR NEW-FORM))
    FORM))

The above definition of MACROEXPAND-1 is oversimplified, since it can
also expand other things, including lambda-macros (the subject of a separate
proposal that has not been sent yet) and possibly implementation-dependent
things (substs in the Lisp machine, for example).

The important point here is the division of labor.  MACROEXPAND-1 takes care
of checking the length of the macro-invocation to make sure it has the right
number of arguments [actually, the implementation is free to choose how much
of this is done by MACROEXPAND-1 and how much is done by code inserted into
the expander function by DEFMACRO].  The hook takes care of memoization.  The
macro expander function is only concerned with translating one form into
another, not with bookkeeping.  It is reasonable for certain kinds of
program-manipulation programs to bind the hook variable.

I introduced a second value from MACROEXPAND-1 instead of making MACROEXPAND
use the traditional EQ test.  Otherwise a subtle change would have been
required to DISPLACING-MACROEXPAND-HOOK, and some writers of hooks might get
it wrong occasionally, and their code would still work 90% of the time.


Other issues:

On page 93 it says that MACROEXPAND ignores local macros established by
MACROLET.  This is clearly incorrect; MACROEXPAND has to get called with an
appropriate lexical context available to it in the same way that EVAL does.
They are both parts of the interpreter.  I don't have anything to propose
about this now; I just want to point out that there is an issue.  I don't
think we need to deal with the issue immediately.

A related issue that must be brought up is whether the Common Lisp subset
should include primitives for accessing and storing macro-expansion
functions.  Currently there is only a special form (MACRO) to set a
macro-expander, and no corresponding function.  The Lisp machine expedient of
using the normal function-definition primitive (FDEFINE) with an argument of
(MACRO . expander) doesn't work in Common Lisp.  Currently there is a gross
way to get the macro expander function, but no reasonable way.  I don't have
a clear feeling whether there are programs that would otherwise be portable
except that they need these operations.
----------------------------------------------------------------

10.  Shall all global system-defined variables have names beginning
and ending with "*", for example *PRINLEVEL* instead of PRINLEVEL
and *READ-DEFAULT-FLOAT-FORMAT* instead of READ←DEFAULT-FLOAT-FORMAT?
	(y) yes   (n) no

11.  Same question for named constants (other than T and NIL), such as
*PI* for PI and *MOST-POSITIVE-FIXNUM* for MOST-POSITIVE-FIXNUM.
	(y) yes   (n) no   (o) yes, but use a character other than "*"

12.  Shall a checking form CHECK-TYPE be introduced as described below?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Thursday, 26 August 1982, 03:04-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>

See p.275 of the 29 July Common Lisp manual and p.275 of the revision
handed out at the Lisp conference.

I suggest that we include CHECK-ARG-TYPE in the language.  Although
CHECK-ARG, CHECK-ARG-TYPE, and ASSERT have partially-overlapping
functionality, each has its own valuable uses and I think all three
ought to be in the language.

Note that CHECK-ARG and CHECK-ARG-TYPE are used when you want explicit
run-time checking, including but not limited to writing the interpreter
(which of course is written in Lisp, not machine language!).

The details:
CHECK-ARG-TYPE arg-name type &OPTIONAL type-string	[macro]

If (TYPEP arg-name 'type) is false, signal an error.  The error message
includes arg-name and a "pretty" English-language form of type, which
can be overridden by specifying type-string (this override is rarely
used).  Proceeding from the error sets arg-name to a new value and
makes the test again.

Currently arg-name must be a variable, but it should be generalized to
any SETF'able place.

type and type-string are not evaluated.

This isn't always used for checking arguments, since the value of any
variable can be checked, but it is usually used for arguments and there
isn't an alternate name that more clearly describes what it does.

Date: 2 Sep 1982 12:30 PDT
From: JonL at PARC-MAXC

PDP10 MacLisp and VAX/NIL have had the name CHECK-TYPE for several 
years for essentially this functionality (unless someone has recently renamed
it).   Since it is used to certify the type of any variable's value,  it did not
include the "-ARG" part.  The motivation was to have a "checker" which was
more succinct than CHECK-ARGS, but which would generally open-code the
type test (and hence introduce no delay to the non-error case).  

I rather prefer the semantics you suggested, namely that the second argument 
to CHECK-TYPE be a type name (given the CommonLisp treatment of type
hierarchy).  At some level, I'd think a "promise" of fast type checking should
be guaranteed (in compiled code) so that persons will prefer to use this
standardized facililty;  without some indication of performance, one would
be tempted to write his own in order not to slow down the common case.
----------------------------------------------------------------

13.  Shall a checking form CHECK-SUBSEQUENCE be introduced as described below?
	(y) yes   (n) no
----------------------------------------------------------------
Date: 2 Sep 1982 12:30 PDT
From: JonL at PARC-MAXC

If the general sequence functions continue to thrive in CommonLisp, I'd
like to suggest that the corresponding CHECK-SUBSEQUENCE macro (or
whatever renaming of it should occur) be included in CommonLisp.  

  CHECK-SUBSEQUENCE (<var> <start-index> <count>) &optional <typename>)

provides a way to certify that <var> holds a sequence datum of the type
<typename>, or of any suitable sequence type (e.g., LIST, or STRING or 
VECTOR etc) if <typename> is null; and that the indicated subsequence
in it is within the size limits.

[GLS: probably <end> is more appropriate than <count> for Common LISP.]
----------------------------------------------------------------

14.  Shall the functions LINE-OUT and STRING-OUT, eliminated in November,
be reinstated?
	(y) yes   (n) no

15.  Shall the REDUCE function be added as described below?
	(y) yes   (n) no
----------------------------------------------------------------
Date:  3 September 1982 1756-EDT (Friday)
From: Guy.Steele at CMU-10A

I would like to mildly re-propose the REDUCE function for Common
LISP, now that adding it would require only one new function, not ten
or fifteen:

REDUCE function sequence &KEY :START :END :FROM-END :INITIAL-VALUE
    The specified subsequence of "sequence" is reduced, using the "function"
    of two arguments.  The reduction is left-associative, unless
    :FROM-END is not false, in which case it is right-associative.
    If the an :INITIAL-VALUE is given, it is logically placed before the
    "sequence" (after it if :FROM-END is true) and included in the
    reduction operation.  If no :INITIAL-VALUE is given, then the "sequence"
    must not be empty.  (An alternative specification: if no :INITIAL-VALUE
    is given, and "sequence" is empty, then "function" is called with
    zero arguments and the result returned.  How about that?  This idea
    courtesy of Dave Touretzky.)

    (REDUCE #'+ '(1 2 3 4)) => 10
    (REDUCE #'- '(1 2 3 4)) => -8
    (REDUCE #'- '(1 2 3 4) :FROM-END T) => -2   ;APL-style
    (REDUCE #'LIST '(1 2 3 4)) => (((1 2) 3) 4)
    (REDUCE #'LIST '(1 2 3 4) :FROM-END T) => (1 (2 (3 4)))
    (REDUCE #'LIST '(1 2 3 4) :INITIAL-VALUE 'FOO) => ((((FOO 1) 2) 3) 4)
    (REDUCE #'LIST '(1 2 3 4) :FROM-END T :INITIAL-VALUE 'FOO)
				 => (1 (2 (3 (4 FOO))))
----------------------------------------------------------------

16.  Shall the Bawden/Moon solution to the "invisible block" problem
be accepted?  The solution is to define (RETURN x) to mean precisely
(RETURN-FROM NIL x), and to specify that essentially all standard
iterators produce blocks named NIL.  A block with a name other than
NIL cannot capture a RETURN, only a RETURN-FROM with a matching name.
	(y) yes   (n) no

17.  Shall the TAGBODY construct be incorporated?  This expresses just
the behavior of the GO aspect of a PROG.  Any atoms in the body
are not evaluated, but serve as tags that may be specified to GO.
Tags have lexical scope and dynamic extent.  TAGBODY always returns NIL.
	(y) yes   (n) no

18.  What shall be done about RESTART?  The following alternatives seem to
be the most popular:
	(a) Have no RESTART form.
	(b) RESTART takes the name of a block.  What happens when you say
	    (RESTART NIL) must be clarified for most iteration constructs.
	(c) There is a new binding form called, say, RESTARTABLE.
	    Within (RESTARTABLE FOO . body), (RESTART FOO) acts as a jump
	    to the top of the body of the enclosing, matching RESTARTABLE form.
	    RESTART tags have lexical scope and dynamic extent.

19.  Shall there be a built-in identity function, and if so, what shall it
be called?
	(c) CR   (i) IDENTITY   (n) no such function

20.  Shall the #*... bit-string syntax replace #"..."?  That is, shall what
was before written #"10010" now be written #*10010 ?
	(y) yes   (n) no

21.  Which of the two outstanding array proposals (below) shall be adopted?
	(s) the "simple" proposal
	(r) the "RPG memorial" proposal
	(m) the "simple" proposal as amended by Moon
----------------------------------------------------------------
*********** "Simple" proposal **********
Date: Thursday, 16 September 1982  23:27-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>

Here is a revision of my array proposal, fixed up in response to some of
the feedback I've received.  See if you like it any better than the
original.  In particular, I have explictly indicated that certain
redundant forms such as MAKE-VECTOR should be retained, and I have
removed the :PRINT keyword, since I now believe that it causes more
trouble than it is worth.  A revised printing proposal appears at the
end of the document.


Arrays can be 1-D or multi-D.  All arrays can be created by MAKE-ARRAY
and can be accessed with AREF.  Storage is done via SETF of an AREF.
The term VECTOR refers to any array of exactly one dimension.
Vectors are special, in that they are also sequences, and can be
referenced by ELT.  Also, only vectors can have fill pointers.

Vectors can be specialized along several distinct axes.  The first is by
the type of the elements, as specified by the :ELEMENT-TYPE keyword to
MAKE-ARRAY.  A vector whose element-type is STRING-CHAR is referred to
as a STRING.  Strings, when they print, use the "..." syntax; they also
are the legal inputs to a family of string-functions, as defined in the
manual.  A vector whose element-type is BIT (alias (MOD 2)), is a
BIT-VECTOR.  These are special because they form the set of legal inputs
to the boolean bit-vector functions.  (We might also want to print them
in a strange way -- see below.)

Some implementations may provide a special, highly efficient
representation for simple vectors.  A simple vector is (of course) 1-D,
cannot have a fill pointer, cannot be displaced, and cannot be altered
in size after its creation.  To get a simple vector, you use the :SIMPLE
keyword to MAKE-ARRAY with a non-null value.  If there are any
conflicting options specified, an error is signalled.  If an
implementation does not support simple vectors, this keyword/value is
ignored except that the error is still signalled on inconsistent cases.

We need a new set of type specifiers for simple things: SIMPLE-VECTOR,
SIMPLE-STRING, and SIMPLE-BIT-VECTOR, with the corresponding
type-predicate functions.  Simple vectors are referenced by AREF in the
usual way, but the user may use THE or DECLARE to indicate at
compile-time that the argument is simple, with a corresponding increase
in efficiency.  Implementations that do not support simple vectors
ignore the "simple" part of these declarations.

Strings (simple or non-simple) self-eval; all other arrays cause an
error when passed to EVAL.  EQUAL descends into strings, but not
into any other arrays.  EQUALP descends into arrays of all kinds,
comparing the corresponding elements with EQUALP.  EQUALP is false
if the array dimensions are not the same, but it is not sensitive to
the element-type of the array, whether it is simple, etc.  In comparing
the dimensions of vectors, EQUALP uses the length from 0 to the fill
pointer; it does not look at any elements beyond the fill pointer.

The set of type-specifiers required for all of this is ARRAY, VECTOR,
STRING, BIT-VECTOR, SIMPLE-VECTOR, SIMPLE-STRING, SIMPLE-BIT-VECTOR.
Each of these has a corresponding type-P predicate, and each can be
specified in list from, along with the element-type and dimension(s).

MAKE-ARRAY takes the following keywords: :ELEMENT-TYPE, :INITIAL-VALUE,
:INITIAL-CONTENTS, :FILL-POINTER, and :SIMPLE.  There is still some
discussion as to whether we should retain array displacement, which
requires :DISPLACED-TO and :DISPLACED-INDEX-OFFSET.

The following functions are redundant, but should be retained for
clarity and emphasis in code: MAKE-VECTOR, MAKE-STRING, MAKE-BIT-VECTOR.
MAKE-VECTOR takes the same keywords as MAKE-ARRAY, but can only take a
single integer as the dimension argument.  MAKE-STRING and
MAKE-BIT-VECTOR are like MAKE-VECTOR, but do not take the :ELEMENT-TYPE
keyword, since the element-type is implicit.  Similarly, we should
retain the forms VREF, CHAR, and BIT, which are identical in operation
to AREF, but which declare their aray argument to be VECTOR, STRING, or
BIT-VECTOR, respectively.

If the :SIMPLE keyword is not specified to MAKE-ARRAY or related forms,
the default is NIL.  However, vectors produced by random forms such as
CONCATENATE are simple, and vectors created when the reader sees #(...)
or "..." are also simple.

As a general rule, arrays are printed in a simple format that, upon
being read back in, produces a form that is EQUALP to the original.
However, some information may be lost in the printing process:
element-type restrictions, whether a vector is simple, whether it has a
fill pointer, whether it is displaced, and the identity of any element
that lies beyond the fill pointer.  This choice was made to favor ease
of interactive use; if the user really wants to preserve in printed form
some complex data structure containing non-simple arrays, he will have
to develop his own printer.

A switch, SUPPRESS-ARRAY-PRINTING, is provided for users who have lots
of large arrays around and don't want to see them trying to print.  If
non-null, this switch causes all arrays except strings to print in a
short, non-readable form that does not include the elements:
#<array-...>.  In addition, the printing of arrays and vectors (but not
of strings) is subject to PRINLEVEL and PRINLENGTH.

Strings, simple or otherwise, print using the "..."  syntax.  Upon
read-in, the "..." syntax creates a simple string.

Bit-vectors, simple or otherwise, print using the #"101010..." syntax.
Upon read-in, this format produces a simple bit-vector.  Bit vectors do
observe SUPPRESS-ARRAY-PRINTING.

All other vectors print out using the #(...) syntax, observing
PRINLEVEL, PRINLENGTH, and SUPPRESS-ARRAY-PRINTING.  This format reads
in as a simple vector of element-type T.

All other arrays print out using the syntax #nA(...), where n is the
number of dimensions and the list is a nest of sublists n levels deep,
with the array elements at the deepest level.  This form observes
PRINLEVEL, PRINLENGTH, and SUPPRESS-ARRAY-PRINTING.  This format reads
in as an array of element-type T.

Query: I am still a bit uneasy about the funny string-like syntax for
bit vectors.  Clearly we need some way to read these in that does not
turn into a type-T vector.  An alternative might be to allow #(...) to
be a vector of element-type T, as it is now, but to take the #n(...)
syntax to mean a vector of element-type (MOD n).  A bit-vector would
then be #2(1 0 1 0...) and we would have a parallel notation available
for byte vectors, 32-bit word vectors, etc.  The use of the #n(...)
syntax to indicate the length of the vector always struck me as a bit
useless anyway.  One flaw in this scheme is that it does not extend to
multi-D arrays.  Before someone suggests it, let me say that I don't
like #nAm(...), where n is the rank and m is the element-type -- it
would be too hard to remember which number was which.  But even with
this flaw, the #n(...) syntax might be useful.

********** "RPG memorial" proposal **********
Date: Thursday, 23 September 1982  00:38-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>

Several people have stated that they dislike my earlier proposal because
it uses the good names (VECTOR, STRING, BIT-VECTOR, VREF, CHAR, BIT) on
general 1-D arrays, and makes the user say "simple" when he wants one of
the more specialized high-efficiency versions.  This makes extra work
for users, who will want simple vectors at least 95% of the time.  In
addition, there is the argument that simple vectors should be thought of
as a first-class data-type (in implementations that provide them) and
not as a mere degenerate form of array.

Just to see what it looks like, I have re-worked the earlier proposal to
give the good names to the simple forms.  This does not really eliminate
any of the classes in the earlier proposal, since each of those classes
had some attributes or operations that distinguished it from the others.

Since there are getting to be a lot of proposals around, we need some
nomencalture for future discussions.  My first attempt, with the
user-settable :PRINT option should be called the "print-switch"
proposal; the next one, with the heavy use of the :SIMPLE switch should
be the "simple-switch" proposal; this one can be called the "RPG
memorial" proposal.  Let me know what you think about this vs. the
simple-switch version -- I can live with either, but I really would like
to nail this down pretty soon so that we can get on with the
implementation.

Arrays can be 1-D or multi-D.  All arrays can be created by MAKE-ARRAY
and can be accessed with AREF.  Storage is done via SETF of an AREF.
1-D arrays are special, in that they are also of type SEQUENCE, and can
be referenced by ELT.  Also, only 1-D arrays can have fill pointers.

Some implementations may provide a special, highly efficient
representation for simple 1-D arrays, which will be of type VECTOR.  A
vector is 1-dimensional, cannot have a fill pointer, cannot be
displaced, and cannot be altered in size after its creation.  To get a
vector, you use the :VECTOR keyword to MAKE-ARRAY with a non-null value.
If there are any conflicting options specified, an error is signalled.
The MAKE-VECTOR form is equivalent to MAKE-ARRAY with :VECTOR T.

A STRING is a VECTOR whose element-type (specified by the :ELEMENT-TYPE
keyword) is STRING-CHAR.  Strings are special in that they print using
the "..." syntax, and they are legal inputs to a class of "string
functions".  Actually, these functions accept any 1-D array whose
element type is STRING-CHAR.  This more general class is called a
CHAR-SEQUENCE. 

A BIT-VECTOR is a VECTOR whose element-type is BIT, alias (MOD 2).
Bit-vectors are special in that they print using the #*... syntax, and
they are legal inputs to a class of boolean bit-vector functions.
Actually, these functions accept any 1-D array whose element-type is
BIT.  This more general class is called a BIT-SEQUENCE.

All arrays can be referenced via AREF, but in some implementations
additional efficiency can be obtained by declaring certain objects to be
vectors, strings, or bit-vectors.  This can be done by normal
type-declarations or by special accessing forms.  The form (VREF v n) is
equivalent to (AREF (THE VECTOR v) n).  The form (CHAR s n) is
equivalent to (AREF (THE STRING s) n).  The form (BIT b n) is equivalent
to (AREF (THE BIT-VECTOR b) n).

If an implementation does not support vectors, the :VECTOR keyword is
ignored except that the error is still signalled on inconsistent cases;
The additional restrictions on vectors are not enforced.  MAKE-VECTOR is
treated just like the equivalent make-array.  VECTORP is true of every
1-D array, STRINGP of every CHAR-SEQUENCE, and BIT-VECTOR of every
BIT-SEQUENCE.

CHAR-SEQUENCEs, including strings, self-eval; all other arrays cause an
error when passed to EVAL.  EQUAL descends into CHAR-SEQUENCEs, but not into
any other arrays.  EQUALP descends into arrays of all kinds, comparing
the corresponding elements with EQUALP.  EQUALP is false if the array
dimensions are not the same, but it is not sensitive to the element-type
of the array, whether it is a vector, etc.  In comparing the dimensions of
vectors, EQUALP uses the length from 0 to the fill pointer; it does not
look at any elements beyond the fill pointer.

The set of type-specifiers required for all of this is ARRAY, VECTOR,
STRING, BIT-VECTOR, SEQUENCE, CHAR-SEQUENCE, and BIT-SEQUENCE.
Each of these has a corresponding type-P predicate, and each can be
specified in list from, along with the element-type and dimension(s).

MAKE-ARRAY takes the following keywords: :ELEMENT-TYPE, :INITIAL-VALUE,
:INITIAL-CONTENTS, :FILL-POINTER, :DISPLACED-TO, :DISPLACED-INDEX-OFFSET,
and :VECTOR.

The following functions are redundant, but should be retained for
clarity and emphasis in code: MAKE-VECTOR, MAKE-STRING, MAKE-BIT-VECTOR.
MAKE-VECTOR takes a single length argument, along with :ELEMENT-TYPE,
:INITIAL-VALUE, and :INITIAL-CONTENTS.  MAKE-STRING and MAKE-BIT-VECTOR
are like MAKE-VECTOR, but do not take the :ELEMENT-TYPE keyword, since
the element-type is implicit.

If the :VECTOR keyword is not specified to MAKE-ARRAY or related forms,
the default is NIL.  However, sequences produced by random forms such as
CONCATENATE are vectors.

Strings always are printed using the "..." syntax.  Bit-vectors always
are printed using the #*... syntax.  Other vectors always print using
the #(...) syntax.  Note that in the latter case, any element-type
restriction is lost upon readin, since this form always produces a
vector of type T when it is read.  However, the new vector will be
EQUALP to the old one.  The #(...) syntax observes PRINLEVEL,
PRINLENGTH, and SUPPRESS-ARRAY-PRINTING.  The latter switch, if non-NIL,
causes the array to print in a non-readable form: #<ARRAY...>.

CHAR-SEQUENCEs print out as though they were strings, using the "..."
syntax.  BIT-SEQUENCES print out as BIT-STRINGS, using the #*... syntax.
All other arrays print out using the #nA(...) syntax, where n is the
number of dimensions and the list is actually a list of lists of lists,
nested n levels deep.  The array elements appear at the lowest level.
The #A syntax also observes PRINLEVEL, PRINLENGTH, and
SUPPRESS-ARRAY-PRINTING.  The #A format reads in as a non-displaced
array of element-type T.

Note that when an array is printed and read back in, the new version is
EQUALP to the original, but some information about the original is lost:
whether the original was a vector or not, element type restrictions,
whether the array was displaced, whether there was a fill pointer, and
the identity of any elements beyond the fill-pointer.  This choice was
made to favor ease of interactive use; if the user really wants to
preserve in printed form some complex data structure containing more
complex arrays, he will have to develop his own print format and printer.

********** Moon revision of "simple" proposal **********
Date: Thursday, 30 September 1982  01:59-EDT
From: MOON at SCRC-TENEX

I prefer the "simple switch" to the "RPG memorial" proposal, with one
modification to be found below.  The reason for this preference is that
it makes the "good" name, STRING for example, refer to the general class
of objects, relegating the efficiency decision to a modifier ("simple").
The alternative makes the efficiency issue too visible to the casual user,
in my opinion.  You have to always be thinking "do I only want this to
work for efficient strings, which are called strings, or should it work
for all kinds of strings, which are called arrays of characters?".
Better to say, "well this works for strings, and hmm, is it worth
restricting it to simple-strings to squeeze out maximal efficiency"?

Lest this seem like I am trying to sabotage the efficiency of Lisp
implementations that are stuck with "stock" hardware, consider the
following:

In the simple switch proposal, how is (MAKE-ARRAY 100) different from
(MAKE-ARRAY 100 :SIMPLE T)?  In fact, there is only one difference--it is
an error to use ADJUST-ARRAY-SIZE on the latter array, but not on the
former.  Except for this, simpleness consists, simply, of the absence of
options.  This suggests to me that the :SIMPLE option be flushed, and
instead a :ADJUSTABLE-SIZE option be added (see, I pronounce the colons).
Even on the Lisp machine, where :ADJUSTABLE-SIZE makes no difference, I
think it would be an improvement, merely for documentation purposes.  Now
everything makes sense: if you don't ask for any special features in your
arrays, you get simple ones, which is consistent with the behavior of the
sequence functions returning simple arrays always.  And if some
implementation decides they need the sequence functions to return
non-simple arrays, they can always add additional keywords to them to so
specify.  The only time you need to know about the word "simple" at all is
if you are making type declarations for efficiency, in which case you have
to decide whether to declare something to be a STRING or a SIMPLE-STRING.
And it makes sense that the more restrictive declaration be a longer word.
This also meets RPG's objection, which I think boils down to the fact
that he thought it was stupid to have :SIMPLE T all over his programs.
He was right.

I'm fairly sure that I don't understand the portability issues that KMP
brought up (I don't have a whole lot of time to devote to this).  But I
think that in my proposal STRINGP and SIMPLE-STRINGP are never the same
in any implementation; for instance, in the Lisp machine STRINGP is true
of all strings, while SIMPLE-STRINGP is only true of those that do not
have fill-pointers.  If we want to legislate that the :ADJUSTABLE-SIZE
option is guaranteed to turn off SIMPLE-STRINGP, I expect I can dig up
a bit somewhere to remember the value of the option.  This would in fact
mean that simple-ness is a completely implementation-independent concept,
and the only implementation-dependence is how much (if any) efficiency
you gain by using it, and how much of that efficiency you get for free
and how much you get only if you make declarations.

Perhaps the last sentence isn't obvious to everyone.  On the LM-2 Lisp
machine, a simple string is faster than a non-simple string for many
operations.  This speed-up happens regardless of declarations; it is a
result of a run-time dispatch to either fast microcode or slow microcode.
On the VAX with a dumb compiler and no tuning, a simple string is only
faster if you make declarations.  On the VAX with a dumb compiler but some
obvious tuning of sequence and string primitives to move type checks out of
inner loops (making multiple copies of the inner loop), simple strings are
faster for these operations, but still slow for AREF unless you make a type
declaration.  On the VAX with a medium-smart compiler that does the same
sort of tuning on user functions, simple strings are faster for user
functions, too, if you only declare (OPTIMIZE SPEED) [assuming that the
compiler prefers space over speed by default, which is the right choice in
most implementations], and save space as well as time if you go whole hog
and make a type declaration.  On the 3600 Lisp machine, you have sort of a
combination of the first case and the last case.

I also support the #* syntax for bit vectors, rather than the #" syntax.
It's probably mere temporal accident that the simple switch proposal
uses #" while the RPG memorial proposal uses #*.

To sum up:

A vector is a 1-dimensional array.  It prints as #(foo bar) or #<array...>
depending on the value of a switch.

A string is a vector of characters.  It always prints as "foo".  Unlike
all other arrays, strings self-evaluate and are compared by EQUAL.

A bit-vector is a vector of bits.  It always prints as #*101.  Since as
far as I can tell these are redundant with integers, perhaps like integers
they should self-evaluate and be compared by EQUAL.  I don't care.

A simple-vector, simple-string, or simple-bit-vector is one of the above
with none of the following MAKE-ARRAY (or MAKE-STRING) options specified:

	:FILL-POINTER
	:ADJUSTABLE-SIZE
	:DISPLACED-TO
	:LEADER-LENGTH, :LEADER-LIST (in implementations that offer them)

There are type names and predicates for the three simple array types.  In
some implementations using the type declaration gets you more efficient
code that only works for that simple type, which is why these are in the
language at all.  There are no user-visible distinctions associated with
simpleness other than those implied by the absence of the above MAKE-ARRAY
options.
----------------------------------------------------------------

22.  Shall the following proposal for the OPTIMIZE declaration be adopted?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Wednesday, 15 September 1982  20:51-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>

At the meeting I volunteered to produce a new proposal for the OPTIMIZE
declaration.  Actually, I sent out such a proposal a couple of weeks
ago, but somehow it got lost before reaching SU-AI -- both that machine
and CMUC have been pretty flaky lately.  I did not realize that the rest
of you had not seen this proposal until a couple of days ago.
Naturally, this is the one thing I did not keep a copy of, so here is my
reconstruction.  I should say that this proposal is pretty ugly, but it
is the best that I've been able to come up with.  If anyone out there
can do better, feel free.

Guy originally proposed a format like (DECLARE (OPTIMIZE q1 q2 q3)),
where each of the q's is a quality from the set {SIZE, SPEED, SAFETY}.
(He later suggested to me that COMPILATION-SPEED would be a useful
fourth quality.)  The ordering of the qualities tells the system which
to optimize for.  The obvious problem is that you sometimes want to go
for, say, SPEED above all else, but usually you want some level of
compromise.  There is no way in this scheme to specify how strongly the
system should favor one quality over another.  We don't need a lot of
gradations for most compilers, but the simple ordering is not expressive
enough.

One possibility is to simply reserve the OPTIMIZE declaration for the
various implementations, but not to specify what is done with it.  Then
the implementor could specify in the red pages whatever declaration
scheme his compiler wants to follow.  Unfortunately, this means that
such declarations would be of no use when the code is ported to another
Common Lisp, and users would have no portable way to flag that some
function is an inner loop and should be super-fast, or whatever.  The
proposal below tries to provide a crude but adequate optimization
declaration for portable code, while still making it possible for users
to fine-tune the compiler's actions for particular implementations.

What I propose is (DECLARE (OPTIMIZE (qual1 value1) (qual2 value2) ...),
where the qualities are the four mentioned above and each is paired with
a value from 0 to 3 inclusive.  The ordering of the clauses doesn't
matter, and any quality not specified gets a default value of 1.  The
intent is that {1, 1, 1, 1} would be the compiler's normal default --
whatever set of compromises the implementor believes is appropriate for
his user community.  A setting of 0 for some value is an indication that
the associated quality is unimportant in this context and may be
discrimintaed against freely.  A setting of 2 indicates that the quality
should be favored more than normal, and a setting of 3 means to go all
out to favor that quality.  Only one quality should be raised above 1 at
any one time.

The above specification scheme is crude, but sufficiently expressive for
most needs in portable code.  A compiler implementor will have specific
decisions to make -- whether to suppress inline expansions, whether to
type-check the arguments to CAR and CDR, whether to check for overflow
on arithmetic declared to be FIXNUM, whether to run the peephole
optimizer, etc. -- and it is up to him to decide how to tie these
decisions to the above values so as to match the users expressed wishes.
These decision criteria should be spelled out in that implementation's red
pages.  For example, it might be the case that the peephole optimizer is
not run if COMPILER-SPEED > 1, that type checking for the argument to
CAR and CDR is suppressed if SPEED > SAFETY+1, etc.
----------------------------------------------------------------

23.  Shall it be permitted for macros calls to expand into DECLARE forms
and then be recognized as valid declarations?  For example:
(DEFMACRO CUBOIDS (&REST VARS)
  `(DECLARE (TYPE (ARRAY SHORT-FLONUM 3) ,@VARS)
	    (SPECIAL ,@VARS)
	    (OPTIMIZE SPEED)
	    (INLINE HACK-CUBOIDS)))
(DEFUN CUBOID-EXPERT (A B C D)
  (CUBOIDS A C)
  ...)
This would not allows macros calls *within* a DECLARE form, only allow
macros to expand into a DECLARE form.
	(y) yes   (n) no

24.  Shall there be printer control variables ARRAY-PRINLEVEL and
ARRAY-PRINLENGTH to control printing of arrays?  These would not
limit the printing of strings.
	(y) yes   (n) no

25.  Shall lambda macros, as described below, be incorporated into
the language, and if so, shall they occupy the function name space
or a separate name space?
	(f) function name space   (s) separate name space   (n) no lambda macros
----------------------------------------------------------------
Date: Wednesday, 22 September 1982, 02:27-EDT
From: Howard I. Cannon <HIC at SCRC-TENEX at MIT-MC>

This is the documentation I wrote for lambda-macros as I implemented
them on the Lisp Machine.  Please consider this a proposed definition.

Lambda macros may appear in functions where LAMBDA would have previously
appeared.  When the compiler or interpreter detects a function whose CAR
is a lambda macro, they "expand" the macro in much the same way that
ordinary Lisp macros are expanded -- the lambda macro is called with the
function as its argument, and is expected to return another function as
its value.  Lambda macros may be accessed with the (ε3:lambda-macroε*
ε2nameε*) function specifier.

defspec lambda-macro function-spec lambda-list &body body
Analagously with ε3macroε*, defines a lambda macro to be called
ε2function-specε*. ε2lambda-listε* should consist of one variable, which
will be the function that caused the lambda macro to be called.  The
lambda macro must return a function.  For example:

lisp
(lambda-macro ilisp (x)
  `(lambda (&optional ,@(second x) &rest ignore) . ,(cddr x)))
end←lisp

would define a lambda macro called ε3ilispε* which would cause the
function to accept arguments like a standard Interlisp function -- all
arguments are optional, and extra arguments are ignored.  A typical call
would be:

lisp
(fun-with-functional-arg #'(ilisp (x y z) (list x y z)))
end←lisp

Then, any calls to the functional argument that
ε3fun-with-functional-argε* executes will pass arguments as if the
number of arguments did not matter.
end←defspec

defspec deflambda-macro
ε3deflambda-macroε* is like ε3defmacroε*, but defines a lambda macro
instead of a normal macro.
end←defspec

defspec deflambda-macro-displace
ε3deflambda-macro-displaceε* is like ε3defmacro-displaceε*, but defines
a lambda macro instead of a normal macro.
end←defspec

defspec deffunction function-spec lambda-macro-name lambda-list &body body 
ε3deffunctionε* defines a function with an arbitrary lambda macro
instead of ε3lambdaε*.  It takes arguments like ε3defunε*, expect that
the argument immediatly following the function specifier is the name of
the lambda macro to be used.  ε3deffunctionε* expands the lambda macro
immediatly, so the lambda macro must have been previously defined.

For example:

lisp
(deffunction some-interlisp-like-function ilisp (x y z)
  (list x y z))
end←lisp

would define a function called ε3some-interlisp-like-functionε*, that
would use the lambda macro called ε3ilispε*.  Thus, the function would
do no number of arguments checking.
end←defspec
----------------------------------------------------------------

26.  Shall the floating-point manipulations described below be adopted?
	(y) as described by MOON
	(a) as amended (FLOAT-SIGN changed) by GLS
	(n) do not adopt them
----------------------------------------------------------------
Date: Thursday, 30 September 1982  05:55-EDT
From: MOON at SCRC-TENEX

I am not completely happy with the FLOAT-FRACTION, FLOAT-EXPONENT, and
SCALE-FLOAT functions in the Colander edition.  At the meeting in August I
was assigned to make a proposal.  I am slow.

A minor issue is that the range of FLOAT-FRACTION fails to include zero (of
course it has to), and is inclusive at both ends, which means that there
are two possible return values for some numbers.  I guess that this ugliness
has to stay because some implementations require this freedom for hardware
reasons, and it doesn't make a big difference from a numerical analysis point
of view.  My proposal is to include zero in the range and to add a note about
two possible values for numbers that are an exact power of the base.

A more major issue is that some applications that break down a flonum into
a fraction and an exponent, or assemble a flonum from a fraction and an
exponent, are best served by representing the fraction as a flonum, while
others are best served by representing it as an integer.  An example of
the former is a numerical routine that scales its argument into a certain
range.  An example of the latter is a printing routine that must do exact
integer arithmetic on the fraction.

In the agenda for the August meeting it was also proposed that there be
a function to return the precision of the representation of a given flonum
(presumably in bits); this would be in addition to the "epsilon" constants
described on page 143 of the Colander.

A goal of all this is to make it possible to write portable numeric functions,
such as the trigonometric functions and my debugged version of Steele's
totally accurate floating-point number printer.  These would be portable
to all implementations but perhaps not as efficient as hand-crafted routines
that avoided bignum arithmetic, used special machine instructions, avoided
computing to more precision than the machine really has, etc.

Proposal:

SCALE-FLOAT x e -> y

  y = (* x (expt 2.0 e)) and is a float of the same type as x.
  SCALE-FLOAT is more efficient than exponentiating and multiplying, and
  also cannot overflow or underflow unless the final result (y) cannot
  be represented.

  x is also allowed to be a rational, in which case y is of the default
  type (same as the FLOAT function).

  [x being allowed to be a rational can be removed if anyone objects.  But
   note that this function has to be generic across the different float types
   in any case, so it might as well be generic across all number types.]

UNSCALE-FLOAT y -> x e
  The first value, x, is a float of the same type as y.  The second value, e,
  is an integer such that (= y (* x (expt 2.0 e))).

  The magnitude of x is zero or between 1/b and 1 inclusive, where b is the
  radix of the representation: 2 on most machines, but examples of 8 and
  16, and I think 4, exist.  x has the same sign as y.

  It is an error if y is a rational rather than a float, or if y is an
  infinity.  (Leave infinity out of the Common Lisp manual, though).
  It is not an error if y is zero.

FLOAT-MANTISSA x -> f
FLOAT-EXPONENT x -> e
FLOAT-SIGN x -> s
FLOAT-PRECISION x -> p
  f is a non-negative integer, e is an integer, s is 1 or 0.
  (= x (* (SCALE-FLOAT (FLOAT f x) e) (IF (ZEROP S) 1 -1))) is true.
  It is up to the implementation whether f is the smallest possible integer
  (zeros on the right are removed and e is increased), or f is an integer with
  as many bits as the precision of the representation of x, or perhaps a "few"
  more.  The only thing guaranteed about f is that it is non-negative and
  the above equality is true.

  f is non-negative to avoid problems with minus zero.  s is 1 for minus zero
  even though MINUSP is not true of minus zero (otherwise the FLOAT-SIGN function
  would be redundant).

  p is an integer, the number of bits of precision in x.  This is a constant
  for each flonum representation type (except perhaps for variable-precision
  "bigfloats").

  [I am amenable to converting these four functions into one function that
  returns four values if anyone can come up with a name.  EXPLODE-FLOAT is
  the best so far, and it's not very good, especially since the traditional
  EXPLODE function has been flushed from Common Lisp.  Perhaps DECODE-FLOAT.]

  [I am amenable to adding a function that takes f, e, and s as arguments
   and returns x.  It might be called ENCODE-FLOAT or MAKE-FLOAT.  It ought to
   take either a type argument or an optional fourth argument, the way FLOAT
   takes an optional second argument, which is an example of the type to return.]

FTRUNC x -> fp ip
  The FTRUNC function as it is already defined provides the fraction-part and
  integer-part operations.

These functions exist now in the Lisp machines, with different names and slightly
different semantics in some cases.  They are very easy to write.

Comments?  Suggestions for names?

Date:  4 October 1982 2355-EDT (Monday)
From: Guy.Steele at CMU-10A

I support Moon's proposal, but would like to suggest that FLOAT-SIGN
be modified to
	(FLOAT-SIGN x &optional (y (float 1 x)))
	returns z such that x and z have same sign and (= (abs y) (abs z)).
In this way (FLOAT-SIGN x) returns 1.0 or -1.0 of the same format as x,
and FLOAT-SIGN of two arguments is what the IEEE proposal calls COPYSIGN,
a useful function indeed in numerical code.
--Guy
----------------------------------------------------------------

27.  Shall DEFMACRO, DEFSTRUCT, and other defining forms also be
allowed to take documentation strings as possible and appropriate?
	(y) yes   (n) no

28.  Shall the following proposed revision of OPEN keywords be accepted?
	(y) yes   (n) no
----------------------------------------------------------------
Date: Monday, 4 October 1982, 17:08-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>

OPEN takes a filename as its first argument.  The rest of its arguments
are keyword/value pairs.

WITH-OPEN-STREAM's first subform is a list of a variable (to be bound to
a stream), a filename, and the rest of the elements are keyword/value
pairs.

The keywords are as follows, with their possible values and defaults:

:DIRECTION	:INPUT (the default), :OUTPUT, :APPEND, :OVERWRITE, :PROBE
	:INPUT - The file is expected to exist.  Output operations are not allowed.
	:OUTPUT - The file is expected to not exist.  A new file is created.  Input
			operations are not allowed.
	:APPEND - The file is expected to exist.  Input operations are not allowed.
			New characters are appened to the end of the existing file.
	:OVERWRITE - The file is expected to exist.  All operations are allowed.
			The "file pointer" starts at the beginning of the file.
	:PROBE - The file may or may not exist.  Neither input nor output operations
			are allowed.  Furthermore, it is not necessary to close the stream.

:CHARACTERS	T (the default), NIL, :DEFAULT
	T - Open the file for reading/writing of characters.
	NIL - Open the file for reading/writing of bytes (non-negative integers).
	:DEFAULT - Let the file system decide, based on the file it finds.

:BYTE-SIZE	a fixnum or :DEFAULT (the default)
	a fixnum - Use this byte size.
	:DEFAULT - Let the file system decide, based on the file it finds.

:IF-EXISTS	:ERROR (the default), :NEW-VERSION, :RENAME,
		:RENAME-AND-DELETE, :OVERWRITE, :APPEND, :REPLACE
	Ignored if direction is not :OUTPUT.  This tells what to do if the file
	that you're trying to create already exists.
	:ERROR - Signal an error.
	:NEW-VERSION - Create a file with the same filename except with "latest" version.
	:RENAME - Rename the existing file to something else and proceed.
	:RENAME-AND-DELETE - Rename the existing file and delete (but don't expunge,
		if your system has undeletion) it, and proceed.
	:OVERWRITE - Open for :OVERWRITE instead.  (If your file system doesn't have
		this, use :RENAME-AND-DELETE if you have undeletion and :RENAME otherwise.)
	:APPEND - Open for :APPEND instead.
	:REPLACE - Replace the existing file, deleting it when the stream is closed.

:IF-DOES-NOT-EXIST	:ERROR (the default), :CREATE
	Ignored if direction is neither :APPEND nor :OVERWRITE
	:ERROR - Signal an error.
	:CREATE - Create the file and proceed.


Notes:

I renamed :READ-ALTER to :OVERWRITE; :READ-WRITE might also be good.

The :DEFAULT values are very useful, although some systems cannot figure
out this information.  :CHARACTERS :DEFAULT is especially useful for
LOAD.  Having the byte size come from the file only when the option is
missing, as the latest Common Lisp manual says, is undesirable because
it makes things harder for programs that are passing the value of that
keyword argument as computed from an expression.

Example of OPEN:
     (OPEN "f:>dlw>lispm.init" :DIRECTION :OUTPUT)

Example of WITH-OPEN-FILE:
     (WITH-OPEN-FILE (STREAM "f:>dlw>lispm.init" :DIRECTION :OUTPUT) ...)

OPEN can be kept Maclisp compatible by recognizing whether the second
argument is a list or not.  Lisp Machine Lisp does this for the benefit
of old programs.  The new syntax cannot be mistaken for the old one.

I removed :ECHO because we got rid of MAKE-ECHO-STREAM at the last
meeting.

Other options that the Lisp Machine will probably have, and which might
be candidates for Common Lisp, are: :INHIBIT-LINKS, :DELETED,
:PRESERVE-DATES, and :ESTIMATED-SIZE.
----------------------------------------------------------------
-------

∂05-Oct-82  0533	ZVONA at MIT-MC 	/BALLOT/
Date: Tuesday, 5 October 1982  08:32-EDT
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   Guy.STEELE at CMU-20C
Cc:   b.steele at CMU-10A, common-lisp at SU-AI
Subject: /BALLOT/

~xxxxxnxxxxxxxxxxxxxxxxxxxxxx

Explanation:  

Dick Waters' LetS, which he will release imminently, is far superior
to LOOP.  Unlike LOOP, which is basically a hack, it is based on a
strong theory of what loops really are and what their structure is.
Basically it is a compiler which takes code written in terms of
streams and compiles it into efficient iterative code.

I'm not involved in common lisp.  I probably don't get a vote, but
this is one I really care about.
-------

∂05-Oct-82  1002	Guy.Steele at CMU-10A 	Addendum to voting procedure    
Date:  5 October 1982 1257-EDT (Tuesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Addendum to voting procedure

I forgot to provide a way to indicate "no vote" on a question.
Use "-" for this purpose.  So a response might look like:

~ xabyb n-xxb arn-- --ax- xxa-- -x-

Second, I want to emphasize again that this ballot, as with all
previous ballots, is not necessarily a majority-rules vote,
but an attempt to determine for each question whether there is
a general consensus or not.  If there is consensus, I take that
as a mandate to edit the document accordingly; if not, the
question remains open for discussion.
--Guy

∂05-Oct-82  1517	Scott E. Fahlman <Fahlman at Cmu-20c> 	/BALLOT/   
Date: Tuesday, 5 October 1982  18:16-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   steele at CMU-20C
Cc:   common-lisp at SU-AI
Subject: /BALLOT/


~ b n n y y n y y y y y y n y y y y a i y m y y n n a y y
  1 3 1 - 3 * 1 2 - 1 * 2 2 2 1 2 2 * 3 2 2 - 1 1 * 1 2 -  Intensity
  1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8  Issue #

I have included an indication of how much I care about each issue in a
way that I hope will not choke Guy's voting machine.  1 means that I
will happily abide by the will of the majority; 2 means that I have a
definite preference; 3 means that this issue is very important to me; 4
means that this is a non-negotiable issue.  (There are no 4's here.)
- means that there is no other choice presented, and the one that is
presented seems OK.  A * means "see below".  The numbers on the third line
are just index numbers so that I can see what I'm doing.

6: I am in favor of adding the LOOP package as described (once it is
completed) to the language as a portable yellow pages module.  I feel
rather strongly that it is premature to add LOOP to the white pages.

11: Whatever is done about global vars, global constants should be the
same.  I oppose option 3 or any plan to make them look syntactically
different.

18. I now believe that RESTART is more trouble than it is worth.  I am
strongly opposed to any plan, such as option 3, that would add a RESTART
form but make it impossible to use this with the implicit block around a
DEFUN.  If you have to introduce a RESTARTABLE block, you may as
well use PROG/GO.

25: I seem to be unable to locate any explanation of why Lambda macros
are useful enough to be worth the bother.  Looks like needless hair to
me, but I seem to dimly recall some arguments for why they were needed.
I'm not passionately opposed, but every page full of hairy stuff in the
manual hurts us.

∂05-Oct-82  1532	Dave Dyer       <DDYER at USC-ISIB> 	comment on lambda macros    
Date:  5 Oct 1982 1530-PDT
From: Dave Dyer       <DDYER at USC-ISIB>
Subject: comment on lambda macros
To: Fahlman at CMU-20C
cc: common-lisp at SU-AI
In-Reply-To: Your message of Tuesday, 5 October 1982  18:16-EDT


 LAMBDA macros in zetalisp were borrowed from Interlisp to make it
possible to extend lambda-expression syntax to accomodate Interlisp
semantics.  In general, LAMBDA macros allow an arbitrary translation
step before application of a function. Very useful for embedded languages.
There is no hair, just a few simple taps before errors are declared.
-------

∂05-Oct-82  1552	Earl A. Killian <EAK at MIT-MC> 	defun semantics  
Date: 5 October 1982 18:51-EDT
From: Earl A. Killian <EAK at MIT-MC>
Subject: defun semantics
To: common-lisp at SU-AI

Does defun add the function name to the lexical environment of
the body?  Should it?

For example, in

(defun revappend (a b)
  (if (null a)
      b
      (revappend (cdr a) (cons (car a) b))))

is the tail recursion implementable as a simple GO, or must the
system consult the function cell of the symbol REVAPPEND?  I vote
for allowing the GO, i.e. adding REVAPPEND to the lexical
function environment, in effect, defining DEFUN in terms of
LABELS instead of LAMBDA.

∂05-Oct-82  1612	Brian G. Milnes <Milnes at CMU-20C> 	/BALLOT/
Date: Tuesday, 5 October 1982  19:11-EDT
From: Brian G. Milnes <Milnes at CMU-20C>
To:   STEELE at CMU-20C
Cc:   b.steele at CMU-10A, common-lisp at SU-AI
Subject: /BALLOT/

 12345678912345678912345678
~ayxyyynyynnyyxyxxiymyysyyx

	

∂05-Oct-82  1625	Earl A. Killian <EAK at MIT-MC> 	arrays 
Date: 5 October 1982 19:24-EDT
From: Earl A. Killian <EAK at MIT-MC>
Subject: arrays
To: common-lisp at SU-AI

Suggestion: Now that :TYPE to MAKE-ARRAY is :ELEMENT-TYPE,
shouldn't ARRAY-TYPE be ARRAY-ELEMENT-TYPE?  Or perhaps just
ELEMENT-TYPE, in which case it would work for any sequence?  Not
clear that the concept is very useful for generalized sequences
(e.g. ELEMENT-TYPE of a cons would always be T), though it might
find some use in writing new sequence functions.

Question 1: was ARRAY-RESET-FILL-POINTER eliminated by the decision
at the last meeting to use SETF exclusively?  I.e. is it subsumed
by (SETF (ARRAY-ACTIVE-LENGTH A) L)?

Question 2: I'm not sure what resulted from the displaced array
discussion.  My memory tells me that every proposed use of
displaced arrays was countered with an appropriate access
function.  Has anyone a proposed set of new access functions?
Or are even these deemed unnecessary?

∂05-Oct-82  1927	Alan Bawden <ALAN at MIT-MC> 	ZVONA: ~xxxxxnxxxxxxxxxxxxxxxxxxxxxx    
Date: 5 October 1982 22:18-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  ZVONA: ~xxxxxnxxxxxxxxxxxxxxxxxxxxxx
To: ZVONA at MIT-MC
cc: common-lisp at SU-AI

    Date: Tuesday, 5 October 1982  08:32-EDT
    From: ZVONA

    ~xxxxxnxxxxxxxxxxxxxxxxxxxxxx

    Explanation:  

    Dick Waters' LetS, which he will release imminently, is far superior
    to LOOP.  Unlike LOOP, which is basically a hack, it is based on a
    strong theory of what loops really are and what their structure is.
    Basically it is a compiler which takes code written in terms of
    streams and compiles it into efficient iterative code.

Well I think we should flush DO from Common Lisp because in spite of its
utility, it is not "based on a strong theory of what loops really are".

Seriously, I doubt very much that LetS will totally replace LOOP among the
tools I use any more than LOOP replaced DO.  I am sick to death of knee-jerk
anti-LOOPism and I am beginning to irrationally regard it as a plot to disable
me as a programmer by excommunicating my most useful tools.

∂05-Oct-82  2032	Masinter at PARC-MAXC 	Re: keyword pairs and OPEN 
Date:  5-Oct-82 20:31:36 PDT (Tuesday)
From: Masinter at PARC-MAXC
Subject: Re: keyword pairs and OPEN
In-reply-to: dlw at SCRC-TENEX's message of Monday, 4 October 1982, 17:08-EDT
To: common-lisp at SU-AI

Is the :DIRECTION :PROBE a proper function of "OPEN"? It seems semantically
quite different; e.g., :BYTE-SIZE, :CHARACTERS etc seem pretty meaningless.
Tenex/Tops-20 allows for  "give me name of new file"; is that generally useful?

Interlisp separates out the "direction" (ACCESS method) from the "recognition mode" in its OPENFILE. (The Interlisp VM is the best description of OPENFILE). Thus,
an alternative to consider would have key words:

:ACCESS	 - one of :INPUT, :OUTPUT, :APPEND (or ...)
	no default

:RECOG - one of :OLD, :NEW, :OLD/NEW (or ...)
	default depends on :ACCESS

:TYPE - one of :TEXT or :BINARY or :DEFAULT (or ...)
	(default :TEXT)

:BYTE-SIZE (only meaningful and implies :TYPE :BINARY)

I'd then fold in the :IF-EXISTS and :IF-DOES-NOT-EXIST with different
recognition modes.

What most people then want is some notion of a search-path algorithm on
recognition mode :INPUT. This sometimes takes the form of hacking with
the name which is supplied, which perhaps Common Lisp should avoid.



∂05-Oct-82  2317	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	arrays   
Date: Wednesday, 6 October 1982, 01:55-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: arrays
To: common-lisp at SU-AI
In-reply-to: The message of 5 Oct 82 19:24-EDT from Earl A. Killian <EAK at MIT-MC>

    Date: 5 October 1982 19:24-EDT
    From: Earl A. Killian <EAK at MIT-MC>

    Suggestion: Now that :TYPE to MAKE-ARRAY is :ELEMENT-TYPE,
    shouldn't ARRAY-TYPE be ARRAY-ELEMENT-TYPE?  
Yes, definitely.						 
						 Or perhaps just
    ELEMENT-TYPE, in which case it would work for any sequence?  Not
    clear that the concept is very useful for generalized sequences
    (e.g. ELEMENT-TYPE of a cons would always be T), though it might
    find some use in writing new sequence functions.
Probably this is too random, although I wouldn't mind it.

    Question 1: was ARRAY-RESET-FILL-POINTER eliminated by the decision
    at the last meeting to use SETF exclusively?  I.e. is it subsumed
    by (SETF (ARRAY-ACTIVE-LENGTH A) L)?
(SETF (FILL-POINTER surely.

∂06-Oct-82  0106	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN   
Date: Wednesday, 6 October 1982, 04:03-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: Re: keyword pairs and OPEN
To: common-lisp at SU-AI
In-reply-to: The message of 5 Oct 82 23:31-EDT from Masinter at PARC-MAXC

    Date:  5-Oct-82 20:31:36 PDT (Tuesday)
    From: Masinter at PARC-MAXC

    Is the :DIRECTION :PROBE a proper function of "OPEN"? It seems semantically
    quite different; e.g., :BYTE-SIZE, :CHARACTERS etc seem pretty meaningless.
Well, this is a debatable point.  In terms of message passing, a probe stream
has about half the messages that a real-open stream does, and doesn't have any
messages that a real-open stream does not have.  These messages are operations
such as getting and setting attributes of the file.  So you it's reasonable to
think of probing as a subset of opening, or as a separate function.  The Lisp
machine happened to choose the former.
    
    Tenex/Tops-20 allows for  "give me name of new file"; is that generally useful?
Without actually creating it, how could it be?  If someone else does the same
thing they'll get the same name.  If it does actually create it, is this different
in any way from opening in OUTPUT direction?

    Interlisp separates out the "direction" (ACCESS method) from the
    "recognition mode" in its OPENFILE. (The Interlisp VM is the best
    description of OPENFILE). Thus, an alternative to consider would have
    key words:

    :ACCESS	 - one of :INPUT, :OUTPUT, :APPEND (or ...)
	    no default

    :RECOG - one of :OLD, :NEW, :OLD/NEW (or ...)
	    default depends on :ACCESS

This is just the way it works now in the Lisp machine, and it proved to be
totally hard to understand and use.  Having separate keywords for if-exists
and if-does-not-exist was a good idea on Dan's part, in my opinion.

    :TYPE - one of :TEXT or :BINARY or :DEFAULT (or ...)
	    (default :TEXT)

    :BYTE-SIZE (only meaningful and implies :TYPE :BINARY)

    I'd then fold in the :IF-EXISTS and :IF-DOES-NOT-EXIST with different
    recognition modes.

    What most people then want is some notion of a search-path algorithm on
    recognition mode :INPUT. This sometimes takes the form of hacking with
    the name which is supplied, which perhaps Common Lisp should avoid.

If you mean recognition in the sense of filename completion, that CERTAINLY
does not belong as part of OPEN.  It should be a separate function, but
probably Common Lisp is not prepared to standardize things like this yet.
However, I may not have understood your last paragraph.

∂06-Oct-82  0126	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	GLS's change to Moon's floating-point extractors proposal  
Date: Wednesday, 6 October 1982, 04:19-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: GLS's change to Moon's floating-point extractors proposal
To: common-lisp at SU-AI
In-reply-to: The message of 4 Oct 82 23:55-EDT from Guy.Steele at CMU-10A

    Date:  4 October 1982 2355-EDT (Monday)
    From: Guy.Steele at CMU-10A

    I support Moon's proposal, but would like to suggest that FLOAT-SIGN
    be modified to
	    (FLOAT-SIGN x &optional (y (float 1 x)))
	    returns z such that x and z have same sign and (= (abs y) (abs z)).
    In this way (FLOAT-SIGN x) returns 1.0 or -1.0 of the same format as x,
    and FLOAT-SIGN of two arguments is what the IEEE proposal calls COPYSIGN,
    a useful function indeed in numerical code.

This is the SIGNUM function, which already exists on page 125 of the Colander.
If my memory of the past 2 months' discussion is accurate, it was extended
to the 2-argument case; the Colander only allows one argument.

FLOAT-SIGN was intended to be something else, and would return 0 or 1 rather
than 1.0 or -1.0.  Perhaps FLOAT-SIGN is redundant given the existence of
SIGNUM.  There is only one problem with this, which I think I pointed out in
my message: the minus zero in the proposed IEEE standard.  I'm sure that
SIGNUM of this has to be -0.0 rather than -1.0 (although possibly it has
to be +0.0).  And MINUSP of -0.0 has to be NIL.  Furthermore the standard
specially specifies that (= -0.0 0.0) => T.  So if you're writing a portable
floating point number printer, you need some way to know to print a minus
sign for minus zero.  If EQ worked on numbers you could use it.

∂06-Oct-82  0708	Guy.Steele at CMU-10A 	Re: defun semantics   
Date:  6 October 1982 1007-EDT (Wednesday)
From: Guy.Steele at CMU-10A
To: Earl A. Killian <EAK at MIT-MC>
Subject: Re: defun semantics
CC: common-lisp at SU-AI
In-Reply-To: Earl A. Killian's message of 5 Oct 82 17:51-EST

Defining DEFUN to make self-recursive calls not go through the function
cell would making TRACE much less useful on recursive functions.
--Guy

∂06-Oct-82  0732	Guy.Steele at CMU-10A 	FLOAT-SIGN and SIGNUM 
Date:  6 October 1982 1029-EDT (Wednesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: FLOAT-SIGN and SIGNUM

Extending FLOAT-SIGN to two arguments is useful for the same reasons
as extending SIGNUM (though I'm not sure we really voted for the latter).
The handling of -0.0 is the crux, as Moon points out.  I would assume that
	(SIGNUM 0.0) => 0.0		(FLOAT-SIGN 0.0) => 1.0
	(SIGNUM -0.0) => -0.0		(FLOAT-SIGN -0.0) => -1.0
	(SIGNUM 0.0 x) => 0.0		(FLOAT-SIGN 0.0 x) => |x|
	(SIGNUM -0.0 x) => -0.0		(FLOAT-SIGN -0.0 x) => -|x|
which are distinct useful behaviors, I think.
--Guy

∂06-Oct-82  1112	ZVONA at MIT-MC
Date: Wednesday, 6 October 1982  14:00-EDT
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   common-lisp at sail

I wasn't suggesting flushing LOOP, merely postponing its inclusion in
the white pages until people have had time to compare LetS.  I suspect
that almost every LOOP expression can be re-written more perspicuously
with LetS, but this may not be true; in which case both might be
supported, and people could use whichever is appropriate to a problem.
Or it might be decided that since a new iteration macro comes along
every once in a while, none should be set in concrete.

    Well I think we should flush DO from Common Lisp because in spite
    of its utility, it is not "based on a strong theory of what loops
    really are".
Well, if there were something that did more-or-less the same things as
DO, but had a clearer theory of what is going on, wouldn't you
consider flushing DO in favor of it?  At least in your own code?

    Seriously, I doubt very much that LetS will totally replace LOOP
    among the tools I use any more than LOOP replaced DO.  I am sick
    to death of knee-jerk anti-LOOPism and I am beginning to
    irrationally regard it as a plot to disable me as a programmer by
    excommunicating my most useful tools.  

A knee-jerk anti-LOOPist is someone that says "LOOP is a crock" and
doesn't suggest an alternative.  I am not a knee-jerk anti-LOOPist.  I
would use it in preference to DO if that was all that was available.
But I would still rather use something better.  DO&, which I wrote,
had the advantage that the syntax was uniform and modeled on something
understood (DO), whereas LOOP's syntax is higgledy-piggledy and alien
to LISP.  LetS is better because its syntax is exactly that of PURE
LISP EXPRESSIONS.  Examples for flavor:

(defun copylist (list)
  (Rlist (Elist list)))

(defun sum-first-n-integers (n)
  (Rsum (Eint 1 n)))
-------

∂06-Oct-82  1222	Dave Dyer       <DDYER at USC-ISIB> 	votes   
Date:  6 Oct 1982 1222-PDT
From: Dave Dyer       <DDYER at USC-ISIB>
Subject: votes
To: common-lisp at SU-AI


~b n x y x y y y y n n y n x y y y a x x - y y y s - y y 
 0                 1                   2
 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8
-------

∂06-Oct-82  1225	Kent M. Pitman <KMP at MIT-MC> 	insults 
Date: 6 October 1982 15:24-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject: insults
To: zvona at MIT-OZ, common-lisp at SU-AI

it seems to me that expressions like "knee-jerk anti-LOOPist" are highly
unprofessional and have no place in this discussion. they only serve to
divide people into two camps and do very little good. in discussions like
these, where people have taken very strong stands on things, one would
sometimes like a person to ber able to to accept others' views and change
"sides" rapidly. if one "side" or the other is marked by having been called
names, it can only serve to weaken the ability of that person to correctly make
the technically right decision because s/he has to worry about a host
of personal issues that never should have been involved: will i be branded
a LOOPist? will the <x> community no longer like me or listen to my ideas?...

ALAN's remark about the "knee-jerk anti-LOOPist" does worse than imply
that the person condemns LOOP without supplying an alternative, it suggests
that some people obejct to LOOP as a reflex action and implicit in that is
that they do not use their higher brain functions in the decision. It is,
in my estimation, possible to "correctly condemn" a primitive or feature 
without being able to propose an adequate alternative. Certainly it has
happened many times in Common-Lisp discussions.

i don't even mind the clear sarcasm/humor of ALAN's paranoia because no
one's likely to be hurt by that; it's not very pointed. but, please,
resist the urge to do name-calling. with the general level of passion the
individuals in this group have on particular issues, we just can't afford
to lose track of that we're working together, not against each other.

thanks,

∂06-Oct-82  1423	Kent M. Pitman <KMP at MIT-MC> 	defun semantics   
Date: 6 October 1982 17:21-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  defun semantics
To: EAK at MIT-MC, Guy.Steele at CMU-10A
cc: common-lisp at SU-AI

Yet another thing to think about is the 
 (DEFUN FACT (X) (COND ... (T ... (FACT ...) ... )))
 (SETF #'FOO #'FACT)
 (SETF #'FACT #'BAR)
phenomenon. My suspicion is that very few people ever want the behavior where
the recursive call to FACT gets BAR's definition. It would be nice if functions
were more easily renamed in this way.

GLS is right that this thwarts TRACE in its current form, but perhaps a 
scheme can be found for making TRACE do the right thing. I have some ideas
which I'll talk to people about off this list and maybe suggest later when
they're better thought out. But if this could be worked out, I think having
definitions closed over their original name is a good idea.

∂06-Oct-82  1503	MOON at SCRC-TENEX 	suggestions on floating point numbers and hash tables  
Date: Wednesday, 6 October 1982  17:43-EDT
From: MOON at SCRC-TENEX
To:   common-lisp at SU-AI
Subject: suggestions on floating point numbers and hash tables
In-reply-to: The message of 5 Oct 1982 0030-EDT from HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

    Date:  5 Oct 1982 0030-EDT
    From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

    When you see 1.0, it is hard to know what the precision is. We would
    like to make sure that if you write something out and read it back in,
    it is EQUAL to what you started with.  Thus you should consider doing
    one of the following:

      - adopt a convention where you can tell the precision based on the
    	number of digits printed.  E.g. 1.00000 would be single, but
    	1.000000000000000 would be double.
This obnoxes me.

      - always print an exponent marker, or maybe always print it when the
    	it is not the same as READ-DEFAULT-FLOAT-FORMAT.

    (At the moment, we are always supplying an exponent marker when it is
    different from the default.)
Printing an exponent marker if the format is not the default is the right
alternative, I think.  It also happens to be what the Lisp machine does now
(which doesn't matter since we're willing to do anything reasonable).

No matter what you do you can't solve the problem of trying to get the
same precision on a different machine.

    We do not notice any way to write out hash tables.  We suggest that you
    adopt a # syntax for that.  In my opinion, it should be possible to
    write out and read back in as many kinds of user data structures as is
    possible.
I certainly do not want to see hash tables vomited out at me on the terminal.
But I do agree that is reasonable to have a way to put a hash table in a file.
I don't think it is necessary to add a new # syntax; all that is necessary
is a new keyword argument to MAKE-HASH-TABLE that provides the initial
contents (as an alist or something).  #. can then be used to include a hash
table in other data structure being read (i.e. to put one in a place that
is not a form to be evaluated).

    You specify a default packing factor of .8 for hash tables. I wonder
    whether you really want this number to be defined in the manual.
You are absolutely right.  Common Lisp has no business standardizing this.

    Finally, we wonder whether having separate MAKE-xxx-HASH-TABLE functions
    but the same PUT-HASH and GET-HASH for all types is the right way to go.
I have complained about this before.  There should be one function named
MAKE-HASH-TABLE that takes keywords defining the type of hash table you
want, and one set of functions for accessing.  We (the Lisp machine) screwed
up by ever having multiple functions for different kinds of hash tables.

    Although I don't quite know how one would use it, in
    principle it would make sense to put different kinds of items into the
    same hash table using different functions.
Do you really mean this?  I don't see how it can possibly be meaningful.

∂06-Oct-82  1735	Masinter at PARC-MAXC 	Re: /BALLOT/
Date:  6-Oct-82 17:33:19 PDT (Wednesday)
From: Masinter at PARC-MAXC
Subject: Re: /BALLOT/
In-reply-to: STEELE's message of 5 Oct 1982 0041-EDT
To: Steele@cmu-20c
cc: common-lisp@su-ai 

~anyx-xy-yyyy--y-yaiy-nynd-yy
 1234567890123456789012345678

4) :ERROR, :SET-DEFAULT-PATHNAME options to LOAD should be rationalized with
OPEN; the handling here of search paths should logically be handled by passing
on some of the options from LOAD to OPEN rather than having LOAD do special
path-name processing. This is because users who manipulate files want to do
similar hacking, and the mechanism should be common. 

6) I feel strongly that the white pages SHOULD include a LOOP construct.
I care less about which one, but I like most of Moon's proposal better than DO
and what I saw of LetS. I'd get rid of AND and ELSE. I don't understand
if the "COLLECT" lexical scoping includes scoping under macro expansion.

9) this seems right but not quite fully specified, e.g. LAMBDA-MACRO 

25) spec here not consistent with MACROEXPAND proposal

∂06-Oct-82  1828	Scott E. Fahlman <Fahlman at Cmu-20c> 	suggestions on floating point numbers and hash tables   
Date: Wednesday, 6 October 1982  21:27-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: suggestions on floating point numbers and hash tables


I was about to comment on Hedrick's suggestions when Moon popped up and
said exactly what I was going to (except that I was going to be apalled
rather than obnoxed at the first suggestion).  So I second all of Moon's
comments on these items.

∂06-Oct-82  1919	Kent M. Pitman <KMP at MIT-MC> 	/BALLOT/
Date: 6 October 1982 22:18-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  /BALLOT/
To: Guy.Steele at CMU-10A
cc: Common-Lisp at SU-AI

          ~bnyxnnyyx yyyyy-yyci ymxyns-yx
Notes?      * * *  *      *       **  * * (see below)
Sequencing 123456789 0123456789 012345678

(2)  SETF -> SET. I think we should do this, but not at this time.
    
(4)  Load Keywords. I would vote YES except:
     As suggested by someone when it was proposed, any mention of packages
     should be stricken pending the release of a package system specification.
    
(5)  LOOP. As a yellow-pages extension is ok by me. I strongly oppose its
     placement in the white pages.
                 
(9)  MACROEXPAND. I would vote YES except:
     I am uncomfortable with saying that a form returns two
     values and then returning only one (letting the rest default to NIL).
     Does Common-Lisp specify anything on this? In any case, I would ammend
     the (cond ((and (pairp ...) ...) (values (...) t))
               (t form))
     to (cond (...) (t (values form nil))) to make it clear that two values
     are always returned. If this modification is made, I am happy with this
     proposal.

(15) I have no use for this but have no strong objection.

(22) OPTIMIZE. I would vote YES except:
     The use of numbers instead of keywords bothers me. The section saying
     which numbers can be which values and how those values will be interpreted
     seems to FORTRANesque to me. I think these values should be just keywords
     or the tight restrictions on their values should be lifted. The only use
     for numbers would be to allow users a fluid range of possibilities.

(23) DECLARE. I also support allowing multiple declare forms at the top of
     a bind form. ie,
         (LAMBDA (X Y) (DECLARE (SPECIAL X)) (DECLARE (SPECIAL Y))
     for ease in macros. Steele's proposed evaluator did this and it wasn't
     notably expensive.

(26) I haven't thought enough about floating point to comment usefully.

(28) OPEN keywords. I'm postponing judgment on this issue until the 
     currently active CL discussion on this issue subsides.

∂06-Oct-82  2238	Guy.Steele at CMU-10A 	Documentation and error messages
Date:  7 October 1982 0137-EDT (Thursday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Documentation and error messages

I am a bit concerned about a couple of issues relating to English prose
that the LISP spits out to one.  I am primarily concerned that messages
be of an appropriate length and level of detail for the situation.
(No, I am *not* about to propose variables MSGLEVEL and MSGLENGTH!
But something perhaps close to that.)

First, some people have recognized a need for both short and long
forms of documentation for functions, variables, and other things.
For APROPOS applications or a quick reminder, a line or a sentence
is sufficient, and you don't want APROPOS to belch 100 3-paragraph
descriptions at you instead of 100 lines.  On the other hand, for
DESCRIBE and so on, one wants to see a relatively detailed description.

Here is a quicky solution: in DEFUN, for example, let more than one
documentation string appear, in order of increasing detail, thus:
(DEFUN LENGTH (X)
  "Returns the length of the argument as an integer."
  "LENGTH accepts any sequence (a list or a one-dimensional array)
   and returns its length as a non-negative integer (in fact, as a
   fixnum).  If the argument is an array with a fill pointer, LENGTH
   returns the size of the active region of the array, not that of
   the total memory allocated for the array."
  (TYPECASE ...))

This solution is not great.

There is a similar problem with error messages, trying to strike a
balance between conciseness and helpfulness.  It would be better if
it were possible to signal an error with up to three different
messages: a short (one-line) error message, a longer discourse
explaining the nature of the error and possible likely causes,
and a description of how to recover from the error if it is
possible, particularly in the case of correctable errors.  For certain
software that I want to be useable by non-experts, I would be willing
to define a separate function for each possible error, just so that
I would feel free to write lots of helpful information about an
error condition.  Here's an example of what I have in mind:
(DEFUN UNBOUND-VARIABLE-ERROR (VAR)
  (HERROR ("~S unbound variable" VAR)
    ("The special variable ~S is currently unbound (has no value).
      Perhaps the variable ~S is supposed to have a value and does not,
      or perhaps the name of the correct variable was misspelled."
     VAR VAR)
    ("If you return a correction value, it should be the correct symbol
      naming the variable whose value should be used.  If ther name was
      correctly spelled, give that variable a value first and then return
      that name by typing ~:@C.  Otherwise, return the correct name for
      the variable." #\Hyper-Return)))

Maybe I've gone overboard here, but I want it to be possible to
provide a great amount of on-line help to the user so he doesn't
have to scurry to the manual.  On the other hand, the first thing you
see should be short and crisp, to avoid annoying knowledgeable users.

Comments?
--Guy

∂07-Oct-82  1017	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation and error messages    
Date: Thursday, 7 October 1982  13:16-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Documentation and error messages


Despite my earlier opposition to one-line documentation strings, I now
see the need for them.  I agree with Guy that we need short and medium
forms of built-in documentation for functions and short, medium, and
"return value" forms for errors.  These fit nicely into Moon's proposal
for documentation retrieval: in addition to having a DEFUN documentation
accessor, we would also have a SHORT-DEFUN.  (Actually, like many
others, I prefer FUNCTION and VARIABLE to DEFUN and DEFVAR, but that is
a separate issue.)

Guy's proposal for supplying these strings to the error forms sounds OK.
I worry about adding more hair to DEFUN.  Putting the doc string into
DEFUN is cute, and it has had the psychological effect of encouraging
people to use these strings, but it may be time to create a separate
documentation-defining form.  With enough good examples and social
pressure -- nothing gets into the yellow pages unless every user-visible
function and special variable is documented -- we would still get
compliance.

(document foo
  'short-function
"Short documentation for FOO goes here."
  'function
"Long documentation for FOO goes here and just to make this longer
I will include this useless extra clause."
  'algorithm
"Uses the bubbly-quick-foo algorithm, which is O(n log n).  See Knuth,
volume 5.  For small N, you are better off using BAR."
  'bugs
"With an argument of 0, destructively rewinds the disk.")

(defun foo ...)

We probably don't want to go for this many flavors of doc right now, but
it gives us some room to grow in the future.  Of course, for awhile we
would support embedded doc strings in DEFUN as a compatibility measure.
The embedded string would be FUNCTION (or DEFUN) documentation.

-- Scott

∂07-Oct-82  1622	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Documentation and error messages  
Date: Thursday, 7 October 1982, 19:19-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: Documentation and error messages
To: common-lisp at SU-AI
In-reply-to: The message of 7 Oct 82 01:37-EDT from Guy.Steele at CMU-10A,
             The message of 7 Oct 82 13:16-EDT from Fahlman at Cmu-20c

    Date:  7 October 1982 0137-EDT (Thursday)
    From: Guy.Steele at CMU-10A

    First, some people have recognized a need for both short and long
    forms of documentation for functions, variables, and other things.

    Here is a quicky solution: in DEFUN, for example, let more than one
    documentation string appear, in order of increasing detail....
    This solution is not great.
No it's not.  But it would be acceptable.  I think I still prefer
special-casing the first line over this solution, even though it means that
the short documentation string really has to be short (to fit on a line).
The extra complexity doesn't seem to buy anything, and isn't enough
complexity to do anything really hairy.

    There is a similar problem with error messages, trying to strike a
    balance between conciseness and helpfulness....
Your suggested schemes for this fit much more nicely into the Lisp machine
"New error system" than into the bare Lisp you're trying to put them into.
Since Common Lisp is not prepared to adopt such a hairy error system right
now, I suggest that this issue be dropped until next year, rather than
trying to standardize on some kludge.  I certainly do not propose that it
be dropped forever.

    Date: Thursday, 7 October 1982  13:16-EDT
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

    These fit nicely into Moon's proposal
    for documentation retrieval: in addition to having a DEFUN documentation
    accessor, we would also have a SHORT-DEFUN.
No!  No!  No!  Absolutely not.  That word "DEFUN" is telling you how to
interpret the name of the thing whose documentation you are retrieving;
it is the name of a "name space".  It is 100% wrong to multiply the number
of name spaces by the number of kinds of documentation you might want, and
have as many symbols for documentation as we used to have for sequence
functions.  The level of documentation you want should be a separate
argument to the DOCUMENTATION function.

    (Actually, like many
    others, I prefer FUNCTION and VARIABLE to DEFUN and DEFVAR, but that is
    a separate issue.)
In case I haven't stated my case on this before, I will again, and I'll try to
be crystal clear.  I agree with you.  FUNCTION is better than DEFUN, and
VARIABLE is better than DEFVAR.  The problem is that this does not generalize
well to the many other things you would like to document.  Many classes of
named thing that you can define do not have a name for the class, separate
from the name of the defining special form, except perhaps by deleting the
three letters "DEF" from the latter name.  Furthermore if you have names used
only for this, there is a serious problem with remembering abbreviations.  You
probably won't have much trouble remembering whether it's a VARIABLE or a VAR,
and might even be able to remember whether it's a STRUCTURE or a STRUCT, but
when there are 10 or 20 of these, you will not be able to remember two sets of
names for the same thing.  It's even worse when you put in packages.
Also, don't forget that this naming system necessarily has to be extensible to
user-defined classes of things.


This discussion worries me.  The problem is that it looks like we are getting
away from language design per se, and trying to design a standard user
interface.  Certainly you want some standardization there, on the simple
things that everybody understands and agrees on.  But the whole user interface
field can be an impenetrable morass.  There are issues of personal taste and
esthetics.  The ground rules for many user interface issues are dictated
entirely by implementation considerations, such as whether you support only
bitmap terminals, only fast displays, or all kinds of terminals.  Even worse,
they are dictated by what sort of users your system is intended for.  It can
be extremely difficult to come to any sort of agreement on this kind of thing,
because everyone has a different unstated set of assumptions (model in their
head) for what the discussion is about.

In any case I am certain that the Common Lisp working group, or whatever we
are called, is barely able to keep the language design orderly, and certainly
does not have the resources to design a user interface, too.


I feel quite strongly that we need to buckle down and finish the job of
getting a standard language defined, and not get diverted into a lot of
side-issues.  I want to start serious planning of how the Lisp machine system
is going to make the transition to Common Lisp, and there are still an
enormous number of loose ends as well as areas where the language has diverged
from the Colander edition of the manual, but has not yet reached a final
conclusion.  Once we have several actual, working Common Lisp implementations
and the ability to exchange code routinely, we will be in a much better
position to work constructively on user interfaces and other things at that
level.

∂07-Oct-82  1803	MIT VAX/VMS Lisp Implementors <NIL at MIT-ML> 	/BALLOT/
Date: 7 October 1982 21:05-EDT
From: MIT VAX/VMS Lisp Implementors <NIL at MIT-ML>
Subject:  /BALLOT/
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI

~ b n y y - y y y y x x y n y y y y a i y m y y y s - y y
  1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8

(10)  I really like only ONE "*" at the beginning of the name.  I got
tired of shifting for two years ago, but conversely couldn't stand to
not have the specialness of the variable not be obvious.

(11)  Whatever we decide for 10.

∂07-Oct-82  1814	Scott E. Fahlman <Fahlman at Cmu-20c> 	Documentation and error messages    
Date: Thursday, 7 October 1982  21:13-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Cc:   common-lisp at SU-AI
Subject: Documentation and error messages


    ... That word "DEFUN" is telling you how to
    interpret the name of the thing whose documentation you are retrieving;
    it is the name of a "name space".  It is 100% wrong to multiply the number
    of name spaces by the number of kinds of documentation you might want, and
    have as many symbols for documentation as we used to have for sequence
    functions.  The level of documentation you want should be a separate
    argument to the DOCUMENTATION function.

Well, I seem to have misunderstod Moon's proposal on this, but his
position seems rather doctrinaire.  The point, as I see it, is that
simply saying (documentation 'foo) might get you any of several things,
so another argument is required to specify what you really want.  I
don't think we'll end up with 600 of these.

I agree, however, that this whole documentation thing is getting too
hairy, and that for now we probably shouldn't try to put too many
user-environment things into the white pages.  In addition to Moon's
name spaces and this short/long business, we have the whole unresolved
business of reformatting doc strings.  Maybe we should forget the whole
thing.  All that the white pages really need to say is that DEFUN
optionally contains a string that is meant to be documentation, and that
these should not choke your implementation.  Such strings, along with
those from DEFVAR and friends, get printed somehow via the semi-standard
function DESCRIBE, and they may be accessible in other ways.

Maybe in this case less is more.

-- Scott

∂07-Oct-82  1904	BROOKS at MIT-OZ at MIT-MC 	/BALLOT/    
Date:  7 Oct 1982 2203-EDT
From: BROOKS at MIT-OZ at MIT-MC
Subject: /BALLOT/
To: guy.steele at CMU-10A
cc: common-lisp at SU-AI

~ - n y y - n y y y y o y - - y y y a i y r - y - n - y y
  1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8


Note:
On 21 if not "r" then I prefer "m".
-------

∂07-Oct-82  2221	Glenn S. Burke <GSB at MIT-ML> 	[Re: MIT VAX/VMS Lisp Implementors, Ballot]
Date: 8 October 1982 01:23-EDT
From: Glenn S. Burke <GSB at MIT-ML>
Subject: [Re: MIT VAX/VMS Lisp Implementors, Ballot]
To: Common-Lisp at SU-AI

    Date: Thursday, 7 October 1982  21:29-EDT
    From: Scott E. Fahlman <Fahlman at Cmu-20c>
    To:   MIT VAX/VMS Lisp Implementors <NIL at MIT-ML>

    It is nice to know that you speak for the NIL group, but it would also
    be nice to know who is doing the speaking.
----
Oops.  In rapidly decreasing order of significance:  me, George Carrette,
and various other innocent bystanders in the immediate environment who
i flame at on occasion.

∂07-Oct-82  2351	Guy.Steele at CMU-10A 	Documentation and errors, etc.  
Date:  8 October 1982 0251-EDT (Friday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Documentation and errors, etc.

Moon is absolutely right that how to handle errors and documentation
in generality is a very difficult aspect of user interface design.
Now that I've got everyone aware of the issues, I propose to retract
my proposal are far as serious discussion of immediate adoption is
concerned.  Les us press on towards the near goal first.
--Guy

∂08-Oct-82  1101	Skef Wholey <Wholey at CMU-20C> 	Hash tables => Hashing functions
Date: Friday, 8 October 1982  14:00-EDT
From: Skef Wholey <Wholey at CMU-20C>
To:   Common-Lisp at SU-AI
Subject: Hash tables => Hashing functions

Since Common Lisp provides three kinds of hash tables (eq, eql, and equal),
shouldn't it provide three kinds of hashing functions?  It currently provides
only SXHASH (i.e. EQUAL-HASH).

∂08-Oct-82  1111	Skef Wholey <Wholey at CMU-20C> 	Hash tables => Hashing functions
Date: Friday, 8 October 1982  14:00-EDT
From: Skef Wholey <Wholey at CMU-20C>
To:   Common-Lisp at SU-AI
Subject: Hash tables => Hashing functions

Since Common Lisp provides three kinds of hash tables (eq, eql, and equal),
shouldn't it provide three kinds of hashing functions?  It currently provides
only SXHASH (i.e. EQUAL-HASH).

∂08-Oct-82  1524	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Hash tables => Hashing functions    
Date: Friday, 8 October 1982, 17:54-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Hash tables => Hashing functions
To: Wholey at CMU-20C, Common-Lisp at SU-AI
In-reply-to: The message of 8 Oct 82 14:00-EDT from Skef Wholey <Wholey at CMU-20C>

No, because it is very hard/expensive to provide a function that hashes
on EQ (and EQL) in a Lisp with a copying GC.  That's why we provide hash
tabl`βz the system can deal with this but the user can't.  For example,
Lisp Machine hash tables all include a little variable that gets compared
against a global how-many-flips-have-happened counter, and if there has
been a flip since last time, the hash table has to be completely rehashed.
The user should not see this counter, especially not as part of the C.L.
definition.

∂08-Oct-82  1526	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN
Date: Friday, 8 October 1982, 18:06-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Re: keyword pairs and OPEN
To: Masinter at PARC-MAXC, common-lisp at SU-AI
In-reply-to: The message of 5 Oct 82 23:31-EDT from Masinter at PARC-MAXC

    Date:  5-Oct-82 20:31:36 PDT (Tuesday)
    From: Masinter at PARC-MAXC
    :ACCESS	 - one of :INPUT, :OUTPUT, :APPEND (or ...)
	    no default

    :RECOG - one of :OLD, :NEW, :OLD/NEW (or ...)
	    default depends on :ACCESS

I don't understand this.  Please tell me what each combination means.
For example, what if access is INPUT and recog is NEW?  What if access
is OUTPUT (in the sense of create) and recog is OLD?  It is quite
important that the semantics of OPEN be clearly defined so that every
implementation can be consistent.

The existing definition of the Lisp Machine OPEN function looks rather
similar to what you are proposing; its general complexity and
overgenerality have made it incomprehensible, and so the system has
several completely misimplementations, none of which work right.
I was trying to counter this by keeping things simple and obvious.


∂08-Oct-82  1740	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: keyword pairs and OPEN  
Date:  8 Oct 1982 2042-EDT
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: keyword pairs and OPEN
To: dlw at SCRC-TENEX at MIT-MC
cc: Masinter at PARC-MAXC, common-lisp at SU-AI
In-Reply-To: Your message of 8-Oct-82 1837-EDT

Here is an attempt to flesh out the meanings of the flags you mentioned.

    :ACCESS
	This flag indicates what kind of I/O you intend to do with the
	file.  Unless otherwise specified, I/O operations will begin
	at the beginning of the file.
	  input - you are only going to read from it.
	  output - you want to start with an empty file, and write new
		data to it.  (Some operating systems allow two modes of
		writing to a file, one of which clears the file beforehand
		and one of which does not.  Typically "output" means that
		you want a file which is clear.  Indeed the alternative
		may be so bizaare that we don't even want to worry about
		it.)
	  write-only - you are only going to write to it, but any existing
		data should not be cleared.  (This is the one that is so
		bizaare you may choose to ignore it.  Probably it would be
		enough to have update mode.)
	  append - like write-only, but if the file already exists,
		writing will start from the end of the existing data.
		(Logically, this is not required, as it is equivalent to
		a write-only open followed by random access to the end
		of file. However a number of operating systems make
		special provisions for append access to files where you
		would not normally be able to open for output and then
		position to the end of file.  Thus it is a useful
		distinction.) 
	  update - you are going to do both input and output.

    :RECOG
	This flag indicates attributes of the file that may help in
	finding it.
	  old - file must exist, the existing version is used
	  new - file must not exist, it is created
	  old-version - file need not exist.  If it does, the existing
		version is used.  If it does not, the file is created.
	  new-version - file need not exist.  If it does, a new version
		is created.  If it does not, the file is created.
	Lest you think I have designed this specifically for Tops-20,
	which allows multiple versions, these distinctions are also
	meaningful on Tops-10, which does not.  On Tops-10, if the file
	exists, old-version would update the existing file and
	new-version would supercede it with a new one.

	Defaults are:
	  input - old
	  output - new-version
	  write-only - old-version
	  append - old-version
	  update - old-version

	Certain combinations are meaningless.  Others may not be allowed
	by the operating system.  Exactly which combinations are allowed
	is implementation-dependent.  However every implementation is
	required to support the following combinations
	  input, old
	  output, new-version
	and all implementations are strongly urged to implement all 5
	default combinations, plus append/old and update/old.

    :RANDOM-ACCESS 
	This flag indicates that the file will be accessed in some
	manner other than sequentially. I don't need it for Tops-20, but
	I think some operating systems may.  In my opinion we should 
	include it if any system of interest requires it.  Does any?

    :IMAGE
	Most runtime systems end up doing various character processing
	such as removing null characters, turning CRLF into LF, removing
	the parity bit, turning control characters into representations
	with ↑, turning two-character CDC "ASCII" into actual ASCII (if
	anyone is going to do a CDC implementation). This turns all of
	that off and give you characters unchanged.  No doubt
	implementors will choose their own extensions to control
	behavior appropriate for the operating system, but this one
	option seems generally useful enough to put in the language.

INPUT, NEW - this is generally meaningless.  Some implementations
would probably create a zero-length file and give immediate end of
file.  Others might call it an error.  (Do we want to try to define
exactly what happens?  Does anyone understand I/O well enough to try
to make a model at that level of detail?)

OUTPUT, OLD - this one supercedes an existing file.  It guarantees
that the file must exist.  It is possible that some implementations
would not allow it, but I would think it would be meaningful for most.

-------

∂08-Oct-82  1800	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: keyword pairs and OPEN  
Date:  8 Oct 1982 2042-EDT
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: keyword pairs and OPEN
To: dlw at SCRC-TENEX at MIT-MC
cc: Masinter at PARC-MAXC, common-lisp at SU-AI
In-Reply-To: Your message of 8-Oct-82 1837-EDT

Here is an attempt to flesh out the meanings of the flags you mentioned.

    :ACCESS
	This flag indicates what kind of I/O you intend to do with the
	file.  Unless otherwise specified, I/O operations will begin
	at the beginning of the file.
	  input - you are only going to read from it.
	  output - you want to start with an empty file, and write new
		data to it.  (Some operating systems allow two modes of
		writing to a file, one of which clears the file beforehand
		and one of which does not.  Typically "output" means that
		you want a file which is clear.  Indeed the alternative
		may be so bizaare that we don't even want to worry about
		it.)
	  write-only - you are only going to write to it, but any existing
		data should not be cleared.  (This is the one that is so
		bizaare you may choose to ignore it.  Probably it would be
		enough to have update mode.)
	  append - like write-only, but if the file already exists,
		writing will start from the end of the existing data.
		(Logically, this is not required, as it is equivalent to
		a write-only open followed by random access to the end
		of file. However a number of operating systems make
		special provisions for append access to files where you
		would not normally be able to open for output and then
		position to the end of file.  Thus it is a useful
		distinction.) 
	  update - you are going to do both input and output.

    :RECOG
	This flag indicates attributes of the file that may help in
	finding it.
	  old - file must exist, the existing version is used
	  new - file must not exist, it is created
	  old-version - file need not exist.  If it does, the existing
		version is used.  If it does not, the file is created.
	  new-version - file need not exist.  If it does, a new version
		is created.  If it does not, the file is created.
	Lest you think I have designed this specifically for Tops-20,
	which allows multiple versions, these distinctions are also
	meaningful on Tops-10, which does not.  On Tops-10, if the file
	exists, old-version would update the existing file and
	new-version would supercede it with a new one.

	Defaults are:
	  input - old
	  output - new-version
	  write-only - old-version
	  append - old-version
	  update - old-version

	Certain combinations are meaningless.  Others may not be allowed
	by the operating system.  Exactly which combinations are allowed
	is implementation-dependent.  However every implementation is
	required to support the following combinations
	  input, old
	  output, new-version
	and all implementations are strongly urged to implement all 5
	default combinations, plus append/old and update/old.

    :RANDOM-ACCESS 
	This flag indicates that the file will be accessed in some
	manner other than sequentially. I don't need it for Tops-20, but
	I think some operating systems may.  In my opinion we should 
	include it if any system of interest requires it.  Does any?

    :IMAGE
	Most runtime systems end up doing various character processing
	such as removing null characters, turning CRLF into LF, removing
	the parity bit, turning control characters into representations
	with ↑, turning two-character CDC "ASCII" into actual ASCII (if
	anyone is going to do a CDC implementation). This turns all of
	that off and give you characters unchanged.  No doubt
	implementors will choose their own extensions to control
	behavior appropriate for the operating system, but this one
	option seems generally useful enough to put in the language.

INPUT, NEW - this is generally meaningless.  Some implementations
would probably create a zero-length file and give immediate end of
file.  Others might call it an error.  (Do we want to try to define
exactly what happens?  Does anyone understand I/O well enough to try
to make a model at that level of detail?)

OUTPUT, OLD - this one supercedes an existing file.  It guarantees
that the file must exist.  It is possible that some implementations
would not allow it, but I would think it would be meaningful for most.

-------

∂11-Oct-82  1500	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: keyword pairs and OPEN
Date: Monday, 11 October 1982, 17:49-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Re: keyword pairs and OPEN
To: HEDRICK at RUTGERS
Cc: Masinter at PARC-MAXC, common-lisp at SU-AI
In-reply-to: The message of 8 Oct 82 20:42-EDT from Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>

Thank you for your summary.  My analysis is that your :RECOG is just the
same thing as my :IF-EXISTS and :IF-DOES-NOT-EXIST except that I like my
names more, and a few minor details are different.  I intentionally
omitted :IMAGE since I could not think of any definition that would be
portable and aid in the writing of portable programs.  Certainly many
implementations will have their own :OPEN options.

You're quite right that we must specify which values of the defined
options are required for all implementations and which are optional.  I
should probably have done this, but I'll leave it to GLS since he knows
more about the restrictions of the VAX, S-1, and Spice implementations
than I do.

∂11-Oct-82  2005	MOON at SCRC-TENEX 	Re: macro expansion 
Date: Monday, 11 October 1982  22:58-EDT
From: MOON at SCRC-TENEX
To:   Common-Lisp at SU-AI
Subject: Re: macro expansion
In-reply-to: The message of 2 Sep 1982 18:09 PDT from JonL at PARC-MAXC

    Date: 2 Sep 1982 18:09 PDT
    From: JonL at PARC-MAXC
    In-reply-to: Moon at SCRC-TENEX's message of Sunday, 29 August 1982, 21:26-EDT

Sorry for the slow response, I am behind on my mail.  There seemed to be a couple
things in this message that shouldn't be left hanging.

      1) Why not have MACROEXPAND return the second value, as obtained
        from MACROEXPAND-1 ?
That would be all right with me, I just overlooked it when writing the sample code.

        It might even be worthwhile for this second return value, when
        non-null, to distinguish between the case of having actually run the
        expansion function and having found the expansion in some "memoization"
        facililty.
I can't see any point to this one.

      2) We saw the need for a function called FIND-MACRO-DEFINITION,
Having this would be fine with me.  I think the committee decided that this
should not be in the portable language, because only MACROEXPAND-1 should
be calling it, and removed this functionality from MACROP or MACRO-P.  I'd
stick with that unless there is a good reason to put it back in.

      3) ocasionally there is 
        a macro which wants to say "don't memoize me at all".
I don't see the use for this, since the macro can't control when the interpreter
or compiler remembers the macro expansion of a form versus when it calls
MACROEXPAND again.  Or was this only an effiency hack, for macros that somehow
knew that memoization took longer than expanding them?

	I'd say that there
        is a lacuna in your proposal in that you don't exhibit code for the case of   
        traditional memoizing by hashtable -- that will show how the macroexpansion
        function is selectively called depending on the hashtable entry.  
I think I don't understand this; perhaps you could elaborate.  If a hash table
entry is absent, you call the expansion function, otherwise you don't.

      4) we often felt the need for an additional argument to the expansion
        function which tells *why* this macro call is being expanded -- e.g.,
        EVAL, or COMPILE, or  FOR-VALUE, or FOR-EFFECTS etc.  I can't
        characterise all such cases, but GSB, KMP, and RWK may have some
        good inputs here.
That would be nice, but perhaps hard to do in general and consistently across
implementations.  Is there a way to leave room for it for the future?  (I wouldn't
like to do this by passing an extra argument which everyone is supposed to ignore!)

    Point 3 brings up another possibililty -- maybe your current definition of
    *MACROEXPAND-HOOK* is an over-generalization.  That is, why not
    have two hooks, one for testing whether or not a "memoization" is present
    for the macro call in question (and returning it if present), and another hook
    of three arguments namely:
          i) a pointer to the original cell (macro call),
         ii) the already-computed expansion form, and
        iii) a symbol to indicate the reason why the macro call was "expanded"
    I realise that iii) will require more discussion, so maybe now is not the time
    to put it into CommonLisp; also the memoization hook would have to return
    a second value to indicate whether a memo was present.
I don't see what advantage is gained by splitting the hook in half.  Don't forget
that Common Lisp provides a variety of built-in table mechanisms, including hash
tables, so the user doesn't have to implement the table lookup himself the way
he might in Maclisp.

    In any case, I'd rather see the default value for these macro hooks be NIL,
    so that one didn't have to understand the complexities of expansions and
    memoizations just to get the default case (that is, unless someone plans to
    allow NIL as a valid function name and . . . )

Surely each implementation provides the default functions as the initial values
of these variables, rather than each implementation being required to test
explicitly for NIL in the variable.  Actually we could leave the implementation
free to do it either way, and guarantee nothing about the initial values except
that they provide a certain behavior.

∂13-Oct-82  1309	STEELE at CMU-20C 	Ballot results  
Date: 13 Oct 1982 1608-EDT
From: STEELE at CMU-20C
Subject: Ballot results
To: common-lisp at SU-AI

?????????????????????????????????????????????????????????????????????????????
?  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  ?
?  %  =================================================================  %  ?
?  %  =  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  =  %  ?
?  %  =  $  +++++++++++++++++++++++++++++++++++++++++++++++++++++  $  =  %  ?
?  %  =  $  +  ###############################################  +  $  =  %  ?
?  %  =  $  +  #  /////////////////////////////////////////  #  +  $  =  %  ?
?  %  =  $  +  #  /  The October 1982 Common LISP Ballot  /  #  +  $  =  %  ?
?  %  =  $  +  #  /                RESULTS                /  #  +  $  =  %  ?
?  %  =  $  +  #  /////////////////////////////////////////  #  +  $  =  %  ?
?  %  =  $  +  ###############################################  +  $  =  %  ?
?  %  =  $  +++++++++++++++++++++++++++++++++++++++++++++++++++++  $  =  %  ?
?  %  =  $$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$  =  %  ?
?  %  =================================================================  %  ?
?  %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%  ?
?????????????????????????????????????????????????????????????????????????????

Here are the tabulated votes on the October 1982 Common LISP Ballot.  For
each issue the summary vote shown between "***" is what I take to be a
consensus, with a "?" added if I am a bit uncertain.  I will edit the
manual according to these guidelines unless someone screams loudly and
soon over some issue.  A few of the issues had a very mixed response;
these I have labeled "Controversial" and will take no immediate action on.
--Guy

1.  How shall the case for a floating-point exponent specifier
output by PRINT and FORMAT be determined?
	(a) upper case, for example 3.5E6
	(b) lower case, for example 3.5e6
	(c) a switch
	(d) implementation-dependent

Issue 1: *** B? ***
Hedrick: B	Wholey: -	Fahlman: B	Weinreb: B	Killian: B
Zubkoff: C	Moon: B		van Roggen: D	Masinter: A	RMS: B
Dyer: B		Bawden: -	Feinberg: B	Ginder: B	Burke et al.: B
Brooks: -	Gabriel: A	DECLISP: B	Steele: C	Dill: D
Scherlis: -	Pitman: B	Anderson: B

2.  Shall we change the name SETF to be SET?   (y) yes   (n) no

Issue 2: *** N ***
Hedrick: N	Wholey: N	Fahlman: N	Weinreb: N	Killian: X
Zubkoff: Y	Moon: N		van Roggen: Y	Masinter: N	RMS: N
Dyer: N		Bawden: N	Feinberg: N	Ginder: N	Burke et al.: N
Brooks: N	Gabriel: N	DECLISP: N	Steele: N	Dill: N
Scherlis: Y	Pitman: N	Anderson: N

Killian: I have been convinced that renaming SETF to SET would be
wrong because it would require changing lots of old code.  But,
you seem to have ignored the rest of my suggestion in your
ballot, namely eliminating those horrid "F"s at the end of
several function names (INCF, GETF etc.).  If you don't do this,
then you're being inconsistent by not naming PUSH PUSHF, etc.
The "F" at the end of "SETF" would then be there purely for
compatibility, and could be renamed when another Lisp dialect
is designed, years hence.

Pitman: I think we should do this, but not at this time.

RMS: I very strongly do not want to have to change uses of the
traditional function SET in the Lisp machine system.

Feinberg: A better name than SETF (or SET) should be found.

3.  Shall there be a type specifier QUOTE, such that (QUOTE x) = (MEMBER x)?
Then MEMBER can be eliminated; (MEMBER x y z) = (OR 'x 'y 'z).  Also one can
write such things as (OR INTEGER 'FOO) instead of (OR INTEGER (MEMBER FOO)).
	(y) yes   (n) no

Issue 3: *** Y? ***
Hedrick: X	Wholey: Y	Fahlman: N	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: N	Masinter: Y	RMS: -
Dyer: X		Bawden: Y	Feinberg: Y	Ginder: -	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: N	Steele: Y	Dill: Y
Scherlis: Y	Pitman: Y	Anderson: -

4.  Shall MOON's proposal for LOAD keywords, revised as shown below, be used?
	(y) yes   (n) no

Issue 4: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: X	RMS: -
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: X	Anderson: -

Moon: I thought we agreed to make LOAD take a stream as its first argument,
instead of a pathname, and flush the :STREAM keyword.  :ERROR should
control only "file does not exist" errors, not "host down", "directory
does not exist", "illegal character in file name", "no access to file",
and "file cannot be read because of disk error".  Nor should it affect
errors due to evaluation of forms in the file.  So I think it needs a
better name; how about :NONEXISTENT-OK?

Masinter: :ERROR, :SET-DEFAULT-PATHNAME options to LOAD should be
rationalized with OPEN; the handling here of search paths should
logically be handled by passing on some of the options from LOAD to OPEN
rather than having LOAD do special path-name processing. This is because
users who manipulate files want to do similar hacking, and the mechanism
should be common.

Pitman: I would vote YES except: As suggested by someone when it was
proposed, any mention of packages should be stricken pending the release
of a package system specification.

Dill: :PACKAGE & :VERBOSE should be flushed, since they are package system
dependent.

5.  Shall closures over dynamic variables be removed from Common LISP?
	(y) yes   (n) no

Issue 5: *** Y? ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: N	Killian: -
Zubkoff: -	Moon: -		van Roggen: Y	Masinter: -	RMS: -
Dyer: X		Bawden: -	Feinberg: Y	Ginder: Y	Burke et al.: -
Brooks: -	Gabriel: N	DECLISP: Y	Steele: Y	Dill: Y
Scherlis: Y	Pitman: N	Anderson: -

6.  Shall LOOP, as summarized below, be included in Common LISP?
	(y) yes   (n) no

Issue 6: Controversial
Hedrick: N	Wholey: N	Fahlman: N	Weinreb: Y	Killian: Y
Zubkoff: X	Moon: -		van Roggen: N	Masinter: X	RMS: N
Dyer: Y		Bawden: Y	Feinberg: N	Ginder: N	Burke et al.: Y
Brooks: N	Gabriel: X	DECLISP: Y	Steele: N	Dill: N
Scherlis: N	Pitman: N	Anderson: N

Fahlman: I am in favor of adding the LOOP package as described (once it is
completed) to the language as a portable yellow pages module.  I feel
rather strongly that it is premature to add LOOP to the white pages.

Zubkoff: The LOOP macro should be kept in the yellow pages until we've
had a chance to use it for a while and determine whether or not it is the
"right" thing.

Masinter: I feel strongly that the white pages SHOULD include a LOOP construct.
I care less about which one, but I like most of Moon's proposal better than DO
and what I saw of LetS. I'd get rid of AND and ELSE. I don't understand
if the "COLLECT" lexical scoping includes scoping under macro expansion.

Pitman: As a yellow-pages extension is ok by me. I strongly oppose its
placement in the white pages.

Feinberg: We should carefully examine all iteration construct proposals
before committing to any particular one.  I feel strongly about 
this.  I would very much like to see complete documentation
on Loop and any other loop construct which might be included 
in Common Lisp, especially before we decide to incorporate them
into the white pages.

Gabriel: I believe that a LOOP construct of some sort is needed: I am
constantly bumping into the limitations of MacLisp-style DO.  The
Symbolics people claim that LOOP, as defined in the current proposal, is
well thought-out and indispensible. Not having used it particularly, I
cannot pass judgement on this. I advocate putting LOOP into the hottest
regions of the Yellow Pages, meaning that people should use it immediately
so that any improvements to clarity can be made rapidly. The best possible
LOOP should then be moved to the White Pages.
My prejudice is that LOOP code is very difficult to understand. On the
other hand, closures are difficult for many people to understand, and
perhaps the difficulty is due to unfamiliarity in the LOOP case as it is
in the closure case.
In my current programming I do not define my own iteration construct
(though I have in the past) because I've found that other people (such as
myself at a later date) do not readily understand my code when it contains
idiosyncratic control structures.  If we do not standardize on a LOOP
construct soon we will be faced with the fact of many people defining
their own difficult-to-understand control structures.

7.  Regardless of the outcome of the previous question, shall CYCLE
be retained and be renamed LOOP, with the understanding that statements
of the construct must be non-atomic, and atoms as "statements" are
reserved for extensions, and any such extensions must be compatible
with the basic mening as a pure iteration construct?
	(y) yes   (n) no

Issue 7: *** Y? ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: -	Moon: Y		van Roggen: N	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: N	Ginder: -	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: N	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: N

Feinberg: I don't think we should make any commitment at all, even to this
extent.  Loop is too nice a word to give up before we even agree about
installing it into the language.

8.  Shall ARRAY-DIMENSION be changed by exchanging its arguments,
to have the array first and the axis number second, to parallel
other indexing operations?
	(y) yes   (n) no

Issue 8: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: -	RMS: Y
Dyer: Y		Bawden: -	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: -	Pitman: Y	Anderson: Y

9.  Shall MACROEXPAND, as described below, replace the current definition?
	(y) yes   (n) no

Issue 9: *** Y ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: -	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: -	Ginder: -	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: X	Anderson: -

Killian:  This is ok as far as it goes, but I intend to suggest
additions when I find the time.

Masinter: This seems right but not quite fully specified, e.g. LAMBDA-MACRO.

Pitman: I would vote YES except:
I am uncomfortable with saying that a form returns two
values and then returning only one (letting the rest default to NIL).
Does Common-Lisp specify anything on this? In any case, I would ammend
the (cond ((and (pairp ...) ...) (values (...) t))
	  (t form))
to (cond (...) (t (values form nil))) to make it clear that two values
are always returned. If this modification is made, I am happy with this
proposal.

10.  Shall all global system-defined variables have names beginning
and ending with "*", for example *PRINLEVEL* instead of PRINLEVEL
and *READ-DEFAULT-FLOAT-FORMAT* instead of READ←DEFAULT-FLOAT-FORMAT?
	(y) yes   (n) no

Issue 10: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: N
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: X
Dyer: N		Bawden: N	Feinberg: Y	Ginder: Y	Burke et al.: X
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: Y

RMS: I would prefer a character other than *, such as "-".
It is easier to type, and easier to type correctly.

Bawden: I am in favor of variables named *FOO* over variables named FOO only
when that doesn't introduce an incompatibility with existing Lisps.  That is
why I voted NO on 10, because it involved an incompatible change to variables
like PRINLEVEL.  I voted YES for 11 because currently we have no named
constants as far as I know so there is no incompatibility.

Burke et al.: I really like only ONE "*" at the beginning of the name.  I got
tired of shifting for two years ago, but conversely couldn't stand to
not have the specialness of the variable not be obvious.

11.  Same question for named constants (other than T and NIL), such as
*PI* for PI and *MOST-POSITIVE-FIXNUM* for MOST-POSITIVE-FIXNUM.
	(y) yes   (n) no   (o) yes, but use a character other than "*"

Issue 11: Controversial
Hedrick: Y	Wholey: N	Fahlman: Y	Weinreb: Y	Killian: N
Zubkoff: Y	Moon: N		van Roggen: Y	Masinter: Y	RMS: X
Dyer: N		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: X
Brooks: O	Gabriel: Y	DECLISP: Y	Steele: N	Dill: X
Scherlis: -	Pitman: Y	Anderson: Y

Fahlman: Whatever is done about global vars, global constants should be the
same.  I oppose option 3 or any plan to make them look syntactically
different.

Moon: I like to use the stars to mean "someone may bind this" rather than
"don't use this as a local variable name", which is why I voted no on
putting stars around constants.  However, others might disagree with me
and I will defer to the majority.  I do think stars around variable names
are important.

12.  Shall a checking form CHECK-TYPE be introduced as described below?
	(y) yes   (n) no

Issue 12: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: -	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: Y
Scherlis: Y	Pitman: Y	Anderson: Y

13.  Shall a checking form CHECK-SUBSEQUENCE be introduced as described below?
	(y) yes   (n) no

Issue 13: Controversial
Hedrick: N	Wholey: -	Fahlman: N	Weinreb: -	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: -	RMS: -
Dyer: N		Bawden: -	Feinberg: N	Ginder: Y	Burke et al.: N
Brooks: -	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: N
Scherlis: Y	Pitman: Y	Anderson: Y

Feinberg: It seems like we're taking this type checking stuff a little 
too far.  Let the user write his own type checking code, or
make a yellow pages package called Carefully (or Lint) or
something. 

Dill: There should be a succinct way about talking about the contents
of sequences, but this particular one doesn't have the right functionality.
I prefer a regular-expression notation of some form, but don't have it
well enough worked out to propose one.  Lets leave it out of the language
until someone figures out how to do it well.

14.  Shall the functions LINE-OUT and STRING-OUT, eliminated in November,
be reinstated?
	(y) yes   (n) no

Issue 14: *** Y ***
Hedrick: N	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: -	Moon: -		van Roggen: Y	Masinter: -	RMS: -
Dyer: X		Bawden: -	Feinberg: Y	Ginder: -	Burke et al.: Y
Brooks: -	Gabriel: -	DECLISP: Y	Steele: Y	Dill: X
Scherlis: -	Pitman: Y	Anderson: -

15.  Shall the REDUCE function be added as described below?
	(y) yes   (n) no

Issue 15: *** Y ***
Hedrick: N	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: -	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: Y
Scherlis: Y	Pitman: -	Anderson: N

Moon: Should the name be REDUCE, or something else?  Hearn aside, the name
doesn't instantly convey to me what it does.  I haven't come up with an
alternative suggestion, however.

Pitman: I have no use for this but have no strong objection.

16.  Shall the Bawden/Moon solution to the "invisible block" problem
be accepted?  The solution is to define (RETURN x) to mean precisely
(RETURN-FROM NIL x), and to specify that essentially all standard
iterators produce blocks named NIL.  A block with a name other than
NIL cannot capture a RETURN, only a RETURN-FROM with a matching name.
	(y) yes   (n) no

Issue 16: *** Y ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: -	RMS: N
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: -

RMS: I am strongly opposed to anything that would require me to find
all the named PROGs in the Lisp machine system which have simple
RETURNs that return from them.  This would make a lot of extra work
for me.  Please don't impose this on me.

Dill: It seems to me that it ought to be possible to exploit lexical
scoping to solve problems like this in a more general way.  If this is
possible, then this proposeal is redundant.

17.  Shall the TAGBODY construct be incorporated?  This expresses just
the behavior of the GO aspect of a PROG.  Any atoms in the body
are not evaluated, but serve as tags that may be specified to GO.
Tags have lexical scope and dynamic extent.  TAGBODY always returns NIL.
	(y) yes   (n) no

Issue 17: *** Y ***
Hedrick: N	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: X
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: N
Scherlis: -	Pitman: Y	Anderson: Y

RMS: Why must GOBODY [sic] always return NIL just because PROG does?
It is just as easy to make GOBODY return the value of the last form in
it.  We can consider a PROG to expand into a GOBODY followed by a NIL.

Feinberg: A better name than TAGBODY should be found.  

18.  What shall be done about RESTART?  The following alternatives seem to
be the most popular:
	(a) Have no RESTART form.
	(b) RESTART takes the name of a block.  What happens when you say
	    (RESTART NIL) must be clarified for most iteration constructs.
	(c) There is a new binding form called, say, RESTARTABLE.
	    Within (RESTARTABLE FOO . body), (RESTART FOO) acts as a jump
	    to the top of the body of the enclosing, matching RESTARTABLE form.
	    RESTART tags have lexical scope and dynamic extent.

Issue 18: *** A ***
Hedrick: A	Wholey: A	Fahlman: A	Weinreb: A	Killian: A
Zubkoff: A	Moon: A		van Roggen: A	Masinter: A	RMS: C
Dyer: A		Bawden: A	Feinberg: A	Ginder: A	Burke et al.: A
Brooks: A	Gabriel: B	DECLISP: A	Steele: C	Dill: X
Scherlis: -	Pitman: C	Anderson: A

Fahlman: I now believe that RESTART is more trouble than it is worth.  I am
strongly opposed to any plan, such as option 3, that would add a RESTART
form but make it impossible to use this with the implicit block around a
DEFUN.  If you have to introduce a RESTARTABLE block, you may as
well use PROG/GO.

19.  Shall there be a built-in identity function, and if so, what shall it
be called?
	(c) CR   (i) IDENTITY   (n) no such function

Issue 19: *** I ***
Hedrick: I	Wholey: I	Fahlman: I	Weinreb: I	Killian: -
Zubkoff: I	Moon: I		van Roggen: I	Masinter: I	RMS: I
Dyer: X		Bawden: I	Feinberg: I	Ginder: I	Burke et al.: I
Brooks: I	Gabriel: -	DECLISP: I	Steele: I	Dill: X
Scherlis: I	Pitman: I	Anderson: -

RMS: The canonical identity function is now called PROG1, but the name
IDENTITY is ok by me.

20.  Shall the #*... bit-string syntax replace #"..."?  That is, shall what
was before written #"10010" now be written #*10010 ?
	(y) yes   (n) no

Issue 20: *** Y ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: X		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: N	DECLISP: Y	Steele: Y	Dill: Y
Scherlis: Y	Pitman: Y	Anderson: Y

21.  Which of the two outstanding array proposals (below) shall be adopted?
	(s) the "simple" proposal
	(r) the "RPG memorial" proposal
	(m) the "simple" proposal as amended by Moon

Issue 21: *** M? ***
Hedrick: M	Wholey: -	Fahlman: M	Weinreb: M	Killian: M
Zubkoff: M	Moon: M		van Roggen: M	Masinter: -	RMS: M
Dyer: -		Bawden: M	Feinberg: M	Ginder: M	Burke et al.: M
Brooks: R	Gabriel: X	DECLISP: M	Steele: M	Dill: M
Scherlis: M	Pitman: M	Anderson: M

Brooks: if not "r" then I prefer "m".

Gabriel: I prefer the "RPG memorial", but I do not feel so strong
about this that I would sink the Common Lisp effort over it.

22.  Shall the following proposal for the OPTIMIZE declaration be adopted?
	(y) yes   (n) no

Issue 22: *** Y ***
Hedrick: Y	Wholey: -	Fahlman: Y	Weinreb: Y	Killian: N
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: N	RMS: -
Dyer: Y		Bawden: -	Feinberg: N	Ginder: Y	Burke et al.: Y
Brooks: -	Gabriel: Y	DECLISP: Y	Steele: -	Dill: X
Scherlis: N	Pitman: X	Anderson: X

Pitman: I would vote YES except:
The use of numbers instead of keywords bothers me. The section saying
which numbers can be which values and how those values will be interpreted
seems to FORTRANesque to me. I think these values should be just keywords
or the tight restrictions on their values should be lifted. The only use
for numbers would be to allow users a fluid range of possibilities.

Feinberg: Keywords instead of numbers would be nicer.  How about
:dont-care, :low, :medium, :high?

Dill: I don't think that we need an optimize declaration in common lisp.
It's not necessary for portability, and intensely dependent on compiler
implementations.  If we must have one, I strongly favor the Fahlman proposal
over proposals that would have symbolic specifications.

23.  Shall it be permitted for macros calls to expand into DECLARE forms
and then be recognized as valid declarations?
This would not allows macros calls *within* a DECLARE form, only allow
macros to expand into a DECLARE form.
	(y) yes   (n) no

Issue 23: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: -	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: Y

Pitman: I also support allowing multiple declare forms at the top of
a bind form. ie,
   (LAMBDA (X Y) (DECLARE (SPECIAL X)) (DECLARE (SPECIAL Y))
for ease in macros. Steele's proposed evaluator did this and it wasn't
notably expensive.

24.  Shall there be printer control variables ARRAY-PRINLEVEL and
ARRAY-PRINLENGTH to control printing of arrays?  These would not
limit the printing of strings.
	(y) yes   (n) no

Issue 24:  Controversial
Hedrick: N	Wholey: Y	Fahlman: N	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: N	RMS: -
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: -	Gabriel: N	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: N	Anderson: Y

25.  Shall lambda macros, as described below, be incorporated into
the language, and if so, shall they occupy the function name space
or a separate name space?
	(f) function name space   (s) separate name space   (n) no lambda macros

Issue 25: Controversial
Hedrick: N	Wholey: -	Fahlman: N	Weinreb: Y	Killian: F
Zubkoff: -	Moon: S		van Roggen: S	Masinter: D	RMS: S
Dyer: S		Bawden: S	Feinberg: N	Ginder: -	Burke et al.: S
Brooks: N	Gabriel: F	DECLISP: S	Steele: N	Dill: N
Scherlis: -	Pitman: S	Anderson: N

Fahlman: I seem to be unable to locate any explanation of why Lambda macros
are useful enough to be worth the bother.  Looks like needless hair to
me, but I seem to dimly recall some arguments for why they were needed.
I'm not passionately opposed, but every page full of hairy stuff in the
manual hurts us.

Masinter: Spec here not consistent with MACROEXPAND proposal.

Feinberg: Once again, hair that I don't think needs to be standardized on.
I think most users would never need this, and perhaps a better 
way to do this can be thought of.

26.  Shall the floating-point manipulations described below be adopted?
	(y) as described by MOON
	(a) as amended (FLOAT-SIGN changed) by GLS
	(n) do not adopt them

Issue 26: *** A ***
Hedrick: A	Wholey: A	Fahlman: A	Weinreb: A	Killian: A
Zubkoff: A	Moon: Y		van Roggen: A	Masinter: -	RMS: -
Dyer: -		Bawden: -	Feinberg: -	Ginder: A	Burke et al.: -
Brooks: -	Gabriel: A	DECLISP: A	Steele: A	Dill: X
Scherlis: -	Pitman: -	Anderson: Y

Killian: Since TRUNC was renamed TRUNCATE at the last meeting, the
FTRUNC in this proposal would have to become FTRUNCATE.

27.  Shall DEFMACRO, DEFSTRUCT, and other defining forms also be
allowed to take documentation strings as possible and appropriate?
	(y) yes   (n) no

Issue 27: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: Y
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: Y	Pitman: Y	Anderson: Y

28.  Shall the following proposed revision of OPEN keywords be accepted?
	(y) yes   (n) no

Issue 28: *** Y ***
Hedrick: Y	Wholey: Y	Fahlman: Y	Weinreb: Y	Killian: Y
Zubkoff: Y	Moon: Y		van Roggen: Y	Masinter: Y	RMS: -
Dyer: Y		Bawden: Y	Feinberg: Y	Ginder: Y	Burke et al.: Y
Brooks: Y	Gabriel: Y	DECLISP: Y	Steele: Y	Dill: X
Scherlis: -	Pitman: X	Anderson: Y

DECLISP: Either READ-ALTER, READ-WRITE OR UPDATE should replace the :OVERWRITE
keyword for :DIRECTION.  Overwrite suggests that an existing file will be
destroyed by having new data written into the same space.
-------

∂14-Oct-82  2110	Guy.Steele at CMU-10A 	Here is a good idea, I think    
Date: 15 October 1982 0010-EDT (Friday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Here is a good idea, I think

Presumably (EVENP x y)  <=>  (ZEROP (MOD x y)) ?

- - - - Begin forwarded message - - - -
Mail-From: ARPANET host PARC-MAXC received by CMU-10A at 14-Oct-82 20:51:44-EDT
Date: 14-Oct-82 17:52:08 PDT (Thursday)
From: Masinter at PARC-MAXC
Subject: optional argument for EVENP?
To: Guy.Steele@CMU-10A
cc: , Masinter.PA

We've found a need in our system for two-argument EVENP, 

(EVENP n &optional divisor)
	divisor defaults to 2. Predicate returns true if n is an integral multiple
	of divisor.

(ODDP n &optional divisor) is merely (NOT (EVENP n divisor)).

This seems to be a logical extension of MOD.
- - - - End forwarded message - - - -

∂14-Oct-82  2139	Scott E. Fahlman <Fahlman at Cmu-20c> 	Here is a good idea, I think   
Date: Friday, 15 October 1982  00:36-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Here is a good idea, I think


Terrible idea!  Actually, I have no objection to having this function
around, except that is one more built-in function, but you can't be
serious about wanting to call it EVENP/ODDP?  You really want to have
code around containing (evenp 51 17) => T ???   I've been looking at
even numbers for most of my life, and 51 is not one, whatever that other
silly argument says.  Pythagoras would turn over in his triangle if he
saw this.

If this has to happen, call it ZEROP-MOD or some such.  Better yet, make
the users type (zerop (mod ...)).

-- Scott

∂14-Oct-82  2144	Guy.Steele at CMU-10A 	Here is a terrible idea, I think
Date: 15 October 1982 0040-EDT (Friday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Here is a terrible idea, I think

One advantage of making the user type (ZEROP (MOD ...)) is that
it makes clear that he is doing that and not (ZEROP (REMAINDER ...)),
which might also be a distinct useful operation.
--Sigh,
  Guy

∂14-Oct-82  2210	Alan Bawden <ALAN at MIT-MC> 	Here is a good idea, I think  
Date: 15 October 1982 01:02-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Here is a good idea, I think
To: common-lisp at SU-AI

    Date: 15 October 1982 0010-EDT (Friday)
    From: Guy.Steele at CMU-10A
    Re:   Here is a good idea, I think

    Presumably (EVENP x y)  <=>  (ZEROP (MOD x y)) ?

My mathematical training makes me think it more natural to define:

    (ZEROP x y) <=> (ZEROP (MOD x y))

So that you can think of the second argument to ZEROP as specifing the ring
that you are considering the first argument a member of.  In fact, if it
wasn't about 20 years too late, I might suggest

    (PLUS x y m) <=> (MOD (PLUS x y) m)

and so forth for all the other arithmetic functions.  There are some real
benefits to be gained from knowing the modulus before you start to compute
some functions (EXPT for example).

Or do we already have a meaning for the second argument to ZEROP?

∂14-Oct-82  2222	Alan Bawden <ALAN at MIT-MC> 	Here is a good idea, I think  
Date: 15 October 1982 01:02-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Here is a good idea, I think
To: common-lisp at SU-AI

    Date: 15 October 1982 0010-EDT (Friday)
    From: Guy.Steele at CMU-10A
    Re:   Here is a good idea, I think

    Presumably (EVENP x y)  <=>  (ZEROP (MOD x y)) ?

My mathematical training makes me think it more natural to define:

    (ZEROP x y) <=> (ZEROP (MOD x y))

So that you can think of the second argument to ZEROP as specifing the ring
that you are considering the first argument a member of.  In fact, if it
wasn't about 20 years too late, I might suggest

    (PLUS x y m) <=> (MOD (PLUS x y) m)

and so forth for all the other arithmetic functions.  There are some real
benefits to be gained from knowing the modulus before you start to compute
some functions (EXPT for example).

Or do we already have a meaning for the second argument to ZEROP?

∂14-Oct-82  2356	HEDRICK at RUTGERS 	A bunch of lousy ideas   
Date: 15 Oct 1982 0218-EDT
From: HEDRICK at RUTGERS
To: common-lisp at SU-AI
Subject: A bunch of lousy ideas
Message-ID: <"MS10(2107)+GLXLIB1(1130)" 11863919900.50.19.85746 at RUTGERS>

There is already enough of extending functions by adding extra
arguments.  ROUND that does division if you give it an extra argument,
etc.  I know this all sounds clever, and it even looks harmless when you
first see it, since the old function does continue to work.  But I think
it is a lousy idea to make ROUND do division, to make SIGN do whatever
it is that we agreed it would do, and to make EVENP do mod.  This sounds
too much like the classic kludges of the following sort:

(IO-OP FOO-FLAG [COUNT])
  if FOO-FLAG is true, this prints its argument
  if FOO-FLAG is false, it rewinds the nearest magtape the 
	number of frames specified by the argument COUNT
    except if COUNT is non-numeric it is the name of the tape
	drive, and the number of frames to be rewound will be
	found in the global variable *FRAMES*

I think we are better off having a one to one mapping between conceptual
functions and names.
   --------

∂15-Oct-82  0011	HEDRICK at RUTGERS 	A bunch of lousy ideas   
Date: 15 Oct 1982 0218-EDT
From: HEDRICK at RUTGERS
To: common-lisp at SU-AI
Subject: A bunch of lousy ideas
Message-ID: <"MS10(2107)+GLXLIB1(1130)" 11863919900.50.19.85746 at RUTGERS>

There is already enough of extending functions by adding extra
arguments.  ROUND that does division if you give it an extra argument,
etc.  I know this all sounds clever, and it even looks harmless when you
first see it, since the old function does continue to work.  But I think
it is a lousy idea to make ROUND do division, to make SIGN do whatever
it is that we agreed it would do, and to make EVENP do mod.  This sounds
too much like the classic kludges of the following sort:

(IO-OP FOO-FLAG [COUNT])
  if FOO-FLAG is true, this prints its argument
  if FOO-FLAG is false, it rewinds the nearest magtape the 
	number of frames specified by the argument COUNT
    except if COUNT is non-numeric it is the name of the tape
	drive, and the number of frames to be rewound will be
	found in the global variable *FRAMES*

I think we are better off having a one to one mapping between conceptual
functions and names.
   --------

∂15-Oct-82  0110	Kent M. Pitman <KMP at MIT-MC> 	conservatism in extensions  
Date: 15 October 1982 04:10-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject: conservatism in extensions
To: hedrick at RUTGERS
cc: common-lisp at SU-AI

i agree. we should be very skeptical of extending things when there is wide
variety of opinion on the direction that extension should go. certainly at
this phase, extensions of this class are not advisable at all. we can always
later add such functionality in an upward-compatible way; it will be harder
to go back on wrong decisions. right now, we need to get any hard issues
ironed out that are needed to get initial implementations up and running.
once people have played with implementations for a while and we get back
feedback about actual use, then is the time to extend an operation...

∂15-Oct-82  0152	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Here is a tired quux, I think
Date: Friday, 15 October 1982, 04:50-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: Here is a tired quux, I think
To: Guy.Steele at CMU-10A
Cc: common-lisp at SU-AI
In-reply-to: The message of 15 Oct 82 00:40-EDT from Guy.Steele at CMU-10A

    Date: 15 October 1982 0040-EDT (Friday)
    From: Guy.Steele at CMU-10A
    To: common-lisp at SU-AI
    Subject: Here is a terrible idea, I think

    One advantage of making the user type (ZEROP (MOD ...)) is that
    it makes clear that he is doing that and not (ZEROP (REMAINDER ...)),
    which might also be a distinct useful operation.

Did you really just say that?

∂15-Oct-82  1214	The Great Quux at CMU-10A 	Conservatism in extensions  
Date: 15 October 1982 1513-EDT (Friday)
From: The Great Quux at CMU-10A
To: common-lisp at SU-AI
Subject: Conservatism in extensions
Sender: Guy.Steele at CMU-10A
Reply-To: Guy.Steele at CMU-10A

Perhaps we need a predicate GARBAGEP that takes a string.  For example,
	(GARBAGEP "I think GCD should accept complex numbers...") => T.
--Quux

∂15-Oct-82  1233	Guy.Steele at CMU-10A 	Tried Quux vindicated 
Date: 15 October 1982 1516-EDT (Friday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Tried Quux vindicated

Hmm, I see... while REMAINDER and MOD are different in general, they
agree on what is zero.  But in the presence of IEEE floating-point
arithmetic, perhaps (MOD -6.0 3.0) => 0.0 and (REMAINDER -6.0 3.0) => -0.0,
so I think I just barely wiggle out of that one.  It's a pretty
flimsy argument.
(Yes, I was very tired.)

∂16-Oct-82  0001	Alan Bawden <ALAN at MIT-MC> 	Overconservatism in extensions
Date: 16 October 1982 03:01-EDT
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Overconservatism in extensions
To: Common-Lisp at SU-AI

    Date: 15 October 1982 1513-EDT (Friday)
    From: The Great Quux at CMU-10A
    Sender: Guy.Steele at CMU-10A

    Perhaps we need a predicate GARBAGEP that takes a string.  For example,
    	(GARBAGEP "I think GCD should accept complex numbers...") => T.

NO!  This is not a garbage string!  GCD should certainly work on complex
integers.  It is completely consistent to extend GCD in this manner, and I
certainly expected that we would.  It's not even hard.

Or is there some more subtle joke here that I don't understand?  You'll
pardon my confusion, but it seems equally plausible that this is a joke
that I don't appreciate, or that Steele didn't think too hard about an
example of a braindamaged idea.

∂16-Oct-82  1055	The Great Quux at CMU-10A 	Re: Overconservatism in extensions    
Date: 16 October 1982 1351-EDT (Saturday)
From: The Great Quux at CMU-10A
To: Alan Bawden <ALAN at MIT-MC>
Subject: Re: Overconservatism in extensions
CC: common-lisp at SU-AI
Sender: Guy.Steele at CMU-10A
Reply-To: Guy.Steele at CMU-10A
In-Reply-To: Alan Bawden's message of 16 Oct 82 02:01-EST

Okay, how about:
  (GARBAGEP "(GARBAGEP \"I think GCD should accept complex numbers...\") => T")
	=> T
?  Now is everybody happy?
--Quux

∂16-Oct-82  1111	The Great Quux at CMU-10A 	Re: Overconservatism in extensions    
Date: 16 October 1982 1351-EDT (Saturday)
From: The Great Quux at CMU-10A
To: Alan Bawden <ALAN at MIT-MC>
Subject: Re: Overconservatism in extensions
CC: common-lisp at SU-AI
Sender: Guy.Steele at CMU-10A
Reply-To: Guy.Steele at CMU-10A
In-Reply-To: Alan Bawden's message of 16 Oct 82 02:01-EST

Okay, how about:
  (GARBAGEP "(GARBAGEP \"I think GCD should accept complex numbers...\") => T")
	=> T
?  Now is everybody happy?
--Quux

∂17-Oct-82  1255	Guy.Steele at CMU-10A 	What can I say?  
Date: 17 October 1982 1553-EDT (Sunday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: What can I say?


- - - - Begin forwarded message - - - -
Mail-From: ARPANET host MIT-MC received by CMU-10A at 16-Oct-82 23:47:31-EDT
Date: Saturday, 16 October 1982  23:44-EDT
From: MOON at SCRC-TENEX
To:   Guy.Steele at CMU-10A
Subject: Re: Overconservatism in extensions
In-reply-to: The message of 16 Oct 1982 1351-EDT () from The Great Quux at CMU-10A

I presume your latest message was a typo for

	#1= (GARBAGEP #1#)

right?
- - - - End forwarded message - - - -

∂17-Oct-82  2120	Guy.Steele at CMU-10A 	STRING-OUT, LINE-OUT and READLINE    
Date: 18 October 1982 0019-EDT (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: STRING-OUT, LINE-OUT and READLINE

How would people feel about renaming these to WRITE-STRING, WRITE-LINE,
and READ-LINE?  This is in line with other renamings such as WRITE-CHAR.
--Guy

∂17-Oct-82  2303	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	STRING-OUT -> WRITE-STRING, etc.  
Date: Monday, 18 October 1982, 02:01-EDT
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: STRING-OUT -> WRITE-STRING, etc.
To: Guy.Steele at CMU-10A
Cc: common-lisp at SU-AI
In-reply-to: The message of 18 Oct 82 00:19-EDT from Guy.Steele at CMU-10A

We certainly must do this, or forfeit any claim to consistency.  I guess
it just got left off the ballot accidentally, since it was put in at the
last minute at the most recent meeting.  I was probably against it, too.

∂18-Oct-82  1458	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	STRING-OUT, LINE-OUT and READLINE   
Date: Monday, 18 October 1982, 16:20-EDT
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: STRING-OUT, LINE-OUT and READLINE
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-reply-to: The message of 18 Oct 82 00:19-EDT from Guy.Steele at CMU-10A

Yes, they should be renamed as you say.

∂19-Oct-82  1211	George J. Carrette <GJC at MIT-ML> 
Date: 19 October 1982 15:14-EDT
From: George J. Carrette <GJC at MIT-ML>
To: common-lisp at SU-AI

I was wondering..., could AREF and ASET be defined to work on hashtables?
Right now we have at least three conventions defined for referencing an
object via a key or index. We have "properties" working on symbols and
conveniently defined for lists, then arrays, and now hashtables. (Am I
leaving out anything? Alists?) Needing all of these for historical reasons 
or otherwise is ok, but it sure would be nice to have ONE fully generic way of
accessing a "table," especially since other languages make it a point of
providing such a thing.

-gjc

∂20-Oct-82  1612	Earl A. Killian <EAK at MIT-MC> 	Proposed evaluator for Common LISP   
Date: 20 October 1982 19:07-EDT
From: Earl A. Killian <EAK at MIT-MC>
Subject:  Proposed evaluator for Common LISP
To: STEELE at CMU-20C
cc: common-lisp at SU-AI

Common Lisp has not yet, to my knowledge, addressed the problem
of debugging.  With lexical scoping, it is no longer possible to
simply reference variables from a read-eval-print debugging loop,
the standard el cheapo lisp debugger, unless something more is
going on than your proposed evaluator is letting on.  Has this
been thought about yet?  If so, what is being proposed?  It would
be nice if sufficient functionality were provided that *simple*
portable debuggers could be written.

∂20-Oct-82  1700	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: Proposed evaluator for Common LISP
Date: 20 Oct 1982 1959-EDT
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: Proposed evaluator for Common LISP
To: EAK at MIT-MC
cc: STEELE at CMU-20C, common-lisp at SU-AI
In-Reply-To: Your message of 20-Oct-82 1907-EDT

Given proper functions to access scopes up the stack, it is just as easy
to do a debugger for a lexical language as a dynamic language.  We know
this from personal experience, having done a lexically-bound UCI Lisp.
Certainly some adaptation had to be done, but the results were just as
good, and the code wasn't really much worse.
-------

∂20-Oct-82  1743	Earl A. Killian <EAK at MIT-MC> 	Proposed evaluator for Common LISP   
Date: 20 October 1982 20:40-EDT
From: Earl A. Killian <EAK at MIT-MC>
Subject:  Proposed evaluator for Common LISP
To: HEDRICK at RUTGERS
cc: common-lisp at SU-AI

I wasn't asking whether it was doable, but whether anyone was
working on the Common Lisp design for debugging with lexical
scoping.  If you're familiar with an existing winning design,
perhaps you should just submit it as a proposal.

∂27-Oct-82  0010	Guy.Steele at CMU-10A 	Macros and TAGBODY tags    
Date: 27 October 1982 0308-EDT (Wednesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Macros and TAGBODY tags

Shall it be permissible for a macro call to expand into a PROG tag?
(This question arises because macro calls may now expand into declarations.)
I am inclined to say no.

∂27-Oct-82  0012	Guy.Steele at CMU-10A 	SCALE-FLOAT and friends    
Date: 27 October 1982 0310-EDT (Wednesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: SCALE-FLOAT and friends

It was my brain-damage that caused the specification of FLOAT-FRACTION
as returning a number between 1/b (inclusive) and 1 (inclusive).
The latter word obviously should have been "exclusive".  Were both
bounds inclusive, I would have mentioned the qualifier only once.
I will make appropriate amends.
--Guy

∂27-Oct-82  0119	MOON at SCRC-TENEX 	SCALE-FLOAT and friends  
Date: Wednesday, 27 October 1982  04:15-EDT
From: MOON at SCRC-TENEX
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: SCALE-FLOAT and friends
In-reply-to: The message of 27 Oct 1982 0310-EDT () from Guy.Steele at CMU-10A

    Date: 27 October 1982 0310-EDT (Wednesday)
    From: Guy.Steele at CMU-10A
    To: common-lisp at SU-AI
    Subject: SCALE-FLOAT and friends

    It was my brain-damage that caused the specification of FLOAT-FRACTION
    as returning a number between 1/b (inclusive) and 1 (inclusive).
    The latter word obviously should have been "exclusive".  Were both
    bounds inclusive, I would have mentioned the qualifier only once.
    I will make appropriate amends.

I think you're wrong here.  In some floating-point formats, 2's-complement
for instance, the magnitude of the fraction can take on both endpoint
values.  Better to leave it inclusive than to require an implementation
to put in special hair to avoid returning 1.

∂27-Oct-82  0138	MOON at SCRC-TENEX 	Macros and TAGBODY tags  
Date: Wednesday, 27 October 1982  04:18-EDT
From: MOON at SCRC-TENEX
to:   common-lisp at SU-AI
Subject: Macros and TAGBODY tags
In-reply-to: The message of 27 Oct 1982 0308-EDT () from Guy.Steele at CMU-10A

    Date: 27 October 1982 0308-EDT (Wednesday)
    From: Guy.Steele at CMU-10A

    Shall it be permissible for a macro call to expand into a PROG tag?
Absolutely not.

∂27-Oct-82  0141	Kent M. Pitman <KMP at MIT-MC> 	No. Don't let macros expand into prog tags.
Date: 27 October 1982 04:35-EDT
From: Kent M. Pitman <KMP at MIT-MC>
Subject: No. Don't let macros expand into prog tags.
To: Guy.Steele at CMU-10A
cc: COMMON-LISP at SU-AI

No. Macros shouldn't be able to expand to prog tags. An example hopefully 
suffices:

(defmacro do-something-returning-*foo* (&rest ignore) ;dummy definition
 ; just return *foo* for now until we figure out how to implement the something
 '*foo*)

(defun huh? ()
  (prog ()
    (do-something-returning-*foo*) ;supposedly for side-effect
    ...))

this PROG should not be able to be said to have a *FOO* tag. There are probably
many macros that expand into symbols and macro writers should not have to take
the odd context of a prog body expansion into account.

note that this is not contradictory with the idea of letting macros expand
into declare forms because we allow macros to expand only into declare forms
or normal code, but never a mixture. so it's in the semantics of the macro
already that it will be used in a declare position or it won't. macro writers
will not be "surprised" by the context `declare-macros' expand in. the user
will know he has such a macro and will use it right. 

this could be better worded but i'm tired. i hope what i'm saying is 
sufficiently obvious that clarification won't be needed.
-kmp

ps macros expanding into prog tags would also thwart people who wanted to
   implement interpreted go by just doing memq in the relevant prog bodies.

∂27-Oct-82  0704	Scott E. Fahlman <Fahlman at Cmu-20c> 	Macros and TAGBODY tags   
Date: Wednesday, 27 October 1982  10:03-EDT
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Macros and TAGBODY tags


Only if it expands into the whole TAGBODY.
-- Scott

∂04-Nov-82  1413	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Destructuring   
Date: Thursday, 4 November 1982, 10:59-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Destructuring
To: common-lisp at su-ai

Did Common Lisp ever make any desicions regarding destructuring?  In
particular, do any forms do any destructuring at all, and, if so, do
they use the list-directed or evaluation-directed kind?

∂06-Nov-82  1314	Scott E. Fahlman <Fahlman at Cmu-20c> 	Destructuring   
Date: Saturday, 6 November 1982  16:12-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Cc:   common-lisp at SU-AI
Subject: Destructuring


I believe that there are currently no destructuring operations in the
white pages, though implementations are free to add these as
non-standard extensions (or to retain what they already have, if it is
consistent with the current white pages).  I think that the opposition
to destructuring in existing forms such as LAMBDA and LET was (and is)
both strong and deep-rooted.  Most of the opponents would go along with
adding a few new forms that do destructuring (DLET or whatever), but
these never got added.  Suggestions along these lines might make it into
next year's edition of the white pages, but it's too late for the current
go-round, I think -- it would take us awhile to converge on exactly what
destructuring should be used where.

-- Scott

∂08-Nov-82  1424	Guy.Steele at CMU-10A 	Mini-ballot 
Date:  8 November 1982 1649-EST (Monday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Mini-ballot

Here are a few questions that I would like to have answers back
on *** no later than Wednesday evening, November 10 ***.

(1) On the question of function-specs (for things like
like being able to DEFUN a function directly onto a property):
Shall we adopt:
	(a) LISP Machine's style of function specs
		Example:  (DEFUN (:PROPERTY FOO BAR) ...)
	(b) SETF-style function specs
		Example:  (DEFUN (GET 'FOO 'BAR) ...)
	(c) No function specs
?

(2) This is a repetition of issue 11 on the October ballot.
On issue 10 we agreed that global variables shall by convention
have names that begin and end with an asterisk (for example,
*prinlevel*).  Issue 11 was the same question for constants,
and the results were less conclusive, with myself, Moon, Wholey,
and Dyer being the prime opposition to using asterisks.

There is a question as to whether the asterisks are meant to
mean "this is global" or "this is bindable".  Fahlman points
out that when referring to a global object he doesn't want to have
to remember whether it is bindable or not.  My main objection
to surrounding names of constants with asterisks is that T and NIL
would obviously have to be exceptions to the rule, and secondarily
that I prefer to make the distinction between variables and
constants in a visual manner.

Anyway, I'd like to get further feedback on this.
--Guy

∂08-Nov-82  1524	MOON at SCRC-TENEX 	Mini-ballot    
Date: Monday, 8 November 1982  18:10-EST
From: MOON at SCRC-TENEX
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Mini-ballot
In-reply-to: The message of 8 Nov 1982 1649-EST () from Guy.Steele at CMU-10A

(1)  (a) is the right thing.  (c) is okay for now if we can't get agreement.
(b) is wrong-headed and unacceptable.

(2)  I do not feel strongly that constants should not have asterisks,
but I would prefer that they don't so that there is a visual distinction
between constants and variables.  Sometimes it is hard to decide what it
is a constant and what it is a variable, but the Common-Lisp defined
constants such as PI would be better without asterisks.

We could consider a prefix convention for the system-dependent constants
such as MOST-POSITIVE-SINGLE-FLOAT.  I would prefer a package prefix such
as SYS: over the Lisp machine's % or NIL's *: for these.  No prefix would
also be okay.

∂08-Nov-82  1659	Skef Wholey <Wholey at CMU-20C> 	Mini-ballot 
Date: Monday, 8 November 1982  19:17-EST
From: Skef Wholey <Wholey at CMU-20C>
To:   Guy.Steele at CMU-10A
CC:   Common-Lisp at SU-AI
Subject: Mini-ballot

  (A) for #1, the Lisp Machine function specs look OK to me.

  I am attracted to the use of *'s because they emphasize the important events
of binding and refering to dynamic variables.  This emphasis would be lost if
system constants were named in a like manner.  The convention is one that is
certainly worth imitating in user code, as a matter of style.  Constants should
not be named with the * convention for the reason that their values ARE
constant -- no one is likely to clobber them.  Surrounding a name with *'s
makes it possible to determine at a glance whether someone could be clobbering
a variable of yours, or whether you could be tweaking something you shouldn't.

--Skef

∂08-Nov-82  1703	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: Mini-ballot   
Date:  8 Nov 1982 1958-EST
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: Mini-ballot
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI
In-Reply-To: Your message of 8-Nov-82 1649-EST

1) I think I want to vote 3.  I would prefer a separate function,
e.g. (DEFUN-PROP FOO BAR ...), if this is something we really want to
support.  However you ought to consider whether this can be done in
a system-independent fashion.  Presumably you don't define the way
DEFUN is implemented.  Thus you may use EXPR properties or function
definition cells.  So if I specify (:PROPERTY FOO BAR), what is the
value?  A LAMBDA form?  Or possibly something to indicate whether it
is EXPR or MACRO, e.g. (EXPR LAMBDA ...)?  Unless you want to define
the internal form of a function definition (which I would strongly
oppose), the value is likely to be installation dependent.  If so,
then you had better define what it can be used for.  Do you gurantee
that we can always do (APPLY (GET 'FOO 'BAR) args)?  (Not very good
if the property is (EXPR LAMBDA ...))  It is one thing to hide the
implementation of DEFUN.  But it is not good to have a property whose
exact form is undefined.  Thus I recommend against considering this
feature to be part of the white pages.

2) I vote for using a different special character for constants. I think
somebody proposed # #.  I consider it good programming practice to use a
special character to begin all specials, even ones that the user
defines, just so it is immediately obvious to anyone reading the code.  
In addition to that general consideration, it is helpful to emphasize
that this is a system variable.  At a minimum it prevents the user
from choosing the same name himself... 
-------

∂08-Nov-82  1711	Eric Benson <BENSON at UTAH-20> 	Re: Mini-ballot  
Date:  8 Nov 1982 1810-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: Mini-ballot
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-Reply-To: Your message of 8-Nov-82 1449-MST

(1) It should not be necessary to extend DEFUN in this manner.

(SETF (GET 'FOO 'BAR) #'(LAMBDA ...))

should do exactly what you want.  Is there a problem with this?
-------

∂08-Nov-82  1744	Earl A. Killian <EAK at MIT-MC> 	Mini-ballot 
Date: 8 November 1982 20:43-EST
From: Earl A. Killian <EAK at MIT-MC>
Subject:  Mini-ballot
To: MOON at SCRC-TENEX
cc: common-lisp at SU-AI

    Date: Monday, 8 November 1982  18:10-EST
    From: MOON at SCRC-TENEX

    (1)  (a) is the right thing.  (c) is okay for now if we can't get agreement.
    (b) is wrong-headed and unacceptable.


This isn't very helpful without an explanation.  It may be that
adding a new mechanism for something (a) instead of using an old
one (b) is right, but since no one has given any motivation for
doing so, I am unsure what's right about it.

∂08-Nov-82  1743	ZVONA at MIT-MC 	Mini-ballot  
Date: Monday, 8 November 1982  20:39-EST
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   Eric Benson <BENSON at UTAH-20>
Cc:   common-lisp at SU-AI, Guy.Steele at CMU-10A
Subject: Mini-ballot
In-reply-to: The message of 8 Nov 1982  20:10-EST from Eric Benson <BENSON at UTAH-20>

    Date: Monday, 8 November 1982  20:10-EST
    From: Eric Benson <BENSON at UTAH-20>
    To:   Guy.Steele at CMU-10A, common-lisp at SU-AI
    Re:   Mini-ballot

    (1) It should not be necessary to extend DEFUN in this manner.

    (SETF (GET 'FOO 'BAR) #'(LAMBDA ...))

    should do exactly what you want.  Is there a problem with this?

You might as well say that DEFUN should be flushed in favor of 

(SETF (FSYMEVAL 'FOO) #'(LAMBDA ...))

I like the SETF proposal 1(b).  It decreases the amount of syntactic
hair in the language and SETF seems to do exactly what is needed.

Since all my friends dislike it, I must be missing something.

∂08-Nov-82  1756	Scott E. Fahlman <Fahlman at Cmu-20c> 	Mini-ballot
Date: Monday, 8 November 1982  20:56-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: Mini-ballot


 (1) (b) is the right thing.  (c) is okay for now if we can't get agreement.
     (a) Still looks needlessly complex to me, though I could swallow it
     with a few simplifications and the elimination of the locative
     pointer business.  (MOON) is wrong-headed and unacceptable.

 (2) To me, the purpose of the asterisks is to flag those variables that
     are "property of Lisp" so that the user doesn't accidentally
     blunder into them.  I don't need to be reminded which things it
     makes sense to bind, once I see that the variable is part of the
     Lisp system, since that is obvious from the name of the variable.
     I could live with the opposite decision, to have no stars on Lisp
     constants, but would really hate to see them sprout additional
     syntax.

∂08-Nov-82  1803	Kent M. Pitman <KMP at MIT-MC>
Date: 8 November 1982 20:53-EST
From: Kent M. Pitman <KMP at MIT-MC>
To: Benson at UTAH-20
cc: Common-Lisp at SU-AI

In most current Lisp implementations, one cannot write
 (SETF (GET 'FOO 'BAR) #'(LAMBDA ...))
unless he doesn't mind #'(LAMBDA ...) not being compiled. Toplevel
non-definitional forms are not compiled in Maclisp or LispM, for example.
Hence, without the existence of (DEFUN (:PROPERTY FOO BAR) ...), one
would have to write
   (DEFUN something ...)
   (SETF (GET 'FOO 'BAR) #'something)
which is a bit tedious.

I don't know if Common-Lisp has taken a stand on whether toplevel LAMBDAs
like this one get compiled. Discussion came up about it before. It's related
to the (PROGN 'COMPILE ...) issue and should probably be defined. I'm 
personally in favor of avoiding a (PROGN 'COMPILE ...) primitive
and compiling all toplevel forms. In such case, the SETF you show would be
technically correct, but it lacks the declarative appeal of being integrated
into a DEFUN.

The question, I guess, comes down to whether you think of what you're
doing as defining a function with a complex name or creating an
anonymous function and putting it in a complex place. I think there is
need for both and the two issues should be kept separate.

∂08-Nov-82  1846	MOON at SCRC-TENEX 	asterisks around variables    
Date: Monday, 8 November 1982  21:40-EST
From: MOON at SCRC-TENEX
To:   Scott E. Fahlman <Fahlman at Cmu-20c>
Cc:   common-lisp at SU-AI
Subject: asterisks around variables
In-reply-to: The message of 8 Nov 1982  20:56-EST from Scott E. Fahlman <Fahlman at Cmu-20c>

    Date: Monday, 8 November 1982  20:56-EST
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

     (2) To me, the purpose of the asterisks is to flag those variables that
         are "property of Lisp" so that the user doesn't accidentally
         blunder into them.

Hmm, that's an interesting and novel idea.  We handle that by having DEFVAR
complain if you define the same variable in more than one file, and by
using packages to decrease the likelihood of that.  The asterisks are not
there to distinguish the system's variables from the user's variables.
My philosophy is "the fewer magic distinctions between the system and the
user the better; anything the system can do the user should be able to
understand and to change."

∂08-Nov-82  1850	MOON at SCRC-TENEX 	function specs 
Date: Monday, 8 November 1982  21:16-EST
From: MOON at SCRC-TENEX
To:   HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Cc:   common-lisp at SU-AI
Subject: function specs
In-reply-to: The message of 8 Nov 1982 1958-EST from HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

The issues you raise in your message, about system dependence of the
representation of functions, are PRECISELY the reason why there should
be function specs in the language, so that the user need not be aware
of the representation of functions.

Surely the :PROPERTY function spec must mean none other than "if you
do a GET, you will get something you can APPLY and FUNCALL."

∂08-Nov-82  1859	MOON at SCRC-TENEX 	function specs 
Date: Monday, 8 November 1982  21:16-EST
From: MOON at SCRC-TENEX
To:   HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Cc:   common-lisp at SU-AI
Subject: function specs
In-reply-to: The message of 8 Nov 1982 1958-EST from HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

The issues you raise in your message, about system dependence of the
representation of functions, are PRECISELY the reason why there should
be function specs in the language, so that the user need not be aware
of the representation of functions.

Surely the :PROPERTY function spec must mean none other than "if you
do a GET, you will get something you can APPLY and FUNCALL."

∂08-Nov-82  2005	Scott E. Fahlman <Fahlman at Cmu-20c> 	Revised Mini-Ballot  
Date: Monday, 8 November 1982  23:05-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: Revised Mini-Ballot


I find KMP's arguments against option B to be fairly convincing.  It
does not bother me much to have symbols be a special case, but the
business about quoting is serious.  I also believe that the function
specs should be statically analyzable, so we would have to constrain the
SETF forms to be compile-time constant, and that is pretty ugly.  There
is also the problem, mentioned by someone earlier, that the SETF form
makes the user see a level of implementation detail that the
function-spec proposal hides, namely where the function object really
goes.

C has two disadvantages: first, it does not provide for the common case
of wanting to store a compiled function under a property; second, it
will give rise to all sorts of incompatible ad hoc solutions.

So that leaves A.  Things like (defun (:property foo bar) ...) actually
look pretty good to me -- the intent is clear -- and it makes sense for
trace and friends to accept these forms.  I still resist the notion that
these are names, but that is just an issue of how they are explained,
not what the mechanism is.  I guess it also makes sense to make this
facility extensible, and for that we need something like the set of
machinery that Moon proposes.  (This extension stuff should be
documented in such a way that our canonical naive user understands that
he can safely ignore it.)  Of the pre-defined types in the Chine Nual,
we need only :PROPERTY and maybe :INTERNAL.  :LOCATION is clearly out
and :WITHIN and :METHOD should be extensions defined by non-white-pages
packages.

So, if it is kept as simple as possible and explained properly, I guess
I am now prepared to believe that A is best way to go.  (Moon is still
wrong-headed and unacceptable, however -- that HAS to be the wrong
head!)

On the issue of asterisks for constants, I have decided that I really
don't care at all, as long as the issue is settled quickly and
decisively.  I give Guy my proxy to choose between stars and no stars.
I would not like to see a new character convention introduced just for
constants, though.

-- Scott

∂08-Nov-82  2051	Glenn S. Burke <GSB at MIT-ML> 	Mini-ballot  
Date: 8 November 1982 23:49-EST
From: Glenn S. Burke <GSB at MIT-ML>
Subject: Mini-ballot
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI


(1) A.

(2) Mostly i just want a decision made on this.  My feelings are,
approximately in decreasing order of strength:
    Specials should be textually distinguishable from non-specials;  this
significantly helps the case of a user blundering into a system variable
(or worse, constant) just by using it as a LOCAL variable;  this problem
is much more common than "redefining" it with DEFVAR.
    Those which are constants should be textually distinguishable
from those which are parameters.  I've gotten rather accustomed to the
"*" package of NIL in this regard.  Using SYS: simply limits the scope
of naming conflicts (as above) to those things which inherit from SYS
by default (depending on how such things work of course).  I could
see SYS:*MOST-POSITIVE-SINGLE-FLOAT* though, for something (parameter
or constant) which is system-dependent.
    Lastly, i feel rather badly about breaking the Maclisp system
parameters like BASE, IBASE, *NOPOINT, PRINLEVEL, etc.  It was only
the possibility that these would break anyway which has kept me from
dyking out SI:STANDARD-INPUT-RADIX and SI:STANDARD-OUTPUT-RADIX from NIL
and reinstalling IBASE and BASE.

∂08-Nov-82  2308	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: function specs
Date:  9 Nov 1982 0152-EST
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: function specs
To: MOON at SCRC-TENEX at MIT-MC
cc: common-lisp at SU-AI
In-Reply-To: Your message of 8-Nov-82 2121-EST

I am perfectly willing to go with options A or B for DEFUN.  They seem
equally undesireable syntax.  However I would like to have someone define
what the construct for MACRO's, FEXPR's (if Common Lisp has such
things), and any other odd things that DEFUN can generate.  If it is not
possible to do that, then I think we would be better off using (PUTPROP
'FOO 'BAR '#(LAMBDA ...  Furthermore, I would like to request that the
this definition include a specification of the actual data structure to
be used for interpreted functions.  There are two good reasons for this:
  - One good thing about Lisp is supposed to be that programs can
	manipulate code, it seems bad to have functional objects (except
	for compiled code and possibly FUNARG's) be system-dependent.
	(The traditional representation is, of course, LAMBDA
	expressions.)  
  - It is one thing to hide the representation used by (DEFUN FOO, since
	the user can't directly access function definitions (unless he
	happens to know that EXPR properties are used in his
	implementation).  However by definition (DEFUN (:PROPERTY FOO BAR) ..
	is creating a user-visible data structure.  It would be a good
	practice to define what that data structure is.  Clearly in
	some cases (compiled code) it is not reasonable to do so, but
	for interpreted code I claim it is.

I think that in meeting this request you will find it necessary to
define either an MLAMBDA (a lambda for macro's) or a syntax like either
(LAMBDA (%MACRO L)... or (MACRO LAMBDA (L) ....  and the equivalent for
FEXPR's, etc. (if they exist).

This is the reason why I expessed some scepticism about the construct
initially.  

-------

∂09-Nov-82  0000	Guy.Steele at CMU-10A 	Remarks on mini-ballot
Date:  9 November 1982 0245-EST (Tuesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Remarks on mini-ballot

So far, the vote looks like it favors Lisp-Machine-style function specs
if any, and no asterisks around names of constants.

If it will set anyone's mind at rest about constants, the compiler can
detect accidental attempts to bind a constant locally and warn you, but
obviously can't do that for variables that are meant to be bound.  Thus,
from a robustness point of view, it is important to flag variables
visually, but less so to flag constants.

As for runction specs, I find persuasive the remark that if
	(DEFUN (GET FOO BAR) ...)  => (SETF (GET FOO BAR) ...)
then
	(DEFUN FOO ...)  => (SETF FOO ...)
but the latter isn't right.  I formerly favored SETF-style function
specs, but now see how wrong-headed I was.

However, the analogy above also indicates to me that function specs
like (:PROPERTY FOO BAR) really are a kind of generalized name for
a function.  If so, orthogonality demands that they be permissible
in a lot of places where currently I believe they are not in Lisp Machine
LISP:
(a) In FUNCTION:  #'(:PROPERTY FOO BAR) ought to be legal.
(b) As an argument to APPLY:  (APPLY '(:PROPERTY FOO BAR) args).
(c) In ordinary function calls!  ((:PROPERTY FOO BAR) 5 7 :START 3 :END 5)
--Guy

∂09-Nov-82  0055	David A. Moon <Moon at SCRC-POINTER at MIT-MC> 	Remarks on mini-ballot
Date: Tuesday, 9 November 1982, 03:51-EST
From: David A. Moon <Moon at SCRC-POINTER at MIT-MC>
Subject: Remarks on mini-ballot
To: Guy.Steele at CMU-10A
Cc: common-lisp at SU-AI
In-reply-to: The message of 9 Nov 82 02:45-EST from Guy.Steele at CMU-10A

    Date:  9 November 1982 0245-EST (Tuesday)
    From: Guy.Steele at CMU-10A

    However, the analogy above also indicates to me that function specs
    like (:PROPERTY FOO BAR) really are a kind of generalized name for
    a function.  If so, orthogonality demands that they be permissible
    in a lot of places where currently I believe they are not in Lisp Machine
    LISP:
    (a) In FUNCTION:  #'(:PROPERTY FOO BAR) ought to be legal.
It is.  I don't remember there ever being a time when it wasn't, although
I might be forgetting.
    (b) As an argument to APPLY:  (APPLY '(:PROPERTY FOO BAR) args).
    (c) In ordinary function calls!  ((:PROPERTY FOO BAR) 5 7 :START 3 :END 5)
These two aren't, on the theory that the name for a thing is not the thing.
I won't try to argue that this theory is right, but that's the way it is
right at the moment.  The lack of (c) actually required introducing a new
special form, MACROCALL, which is kind of like FUNCALL except that it works
for macros.  Of course if you think about it more precisely, and with proper
understanding of Lisp semantics, this means that MACROCALL is nothing whatever
like FUNCALL!  It's a macro that gets the macro definition of its first subform
and uses it to macro-expand the form.

∂09-Nov-82  0132	Guy.Steele at CMU-10A 	Re: Remarks on mini-ballot 
Date:  9 November 1982 0433-EST (Tuesday)
From: Guy.Steele at CMU-10A
To: David A. Moon <Moon@SCRC-POINTER at MIT-MC>
Subject: Re: Remarks on mini-ballot
CC: common-lisp at SU-AI
In-Reply-To: David A. Moon's message of 9 Nov 82 03:51-EST

I might believe that (APPLY '(:PROPERTY FOO BAR) args) shouldn't work,
on the basis of your argument that the name of the thing is not the same
as the thing (true enough), except that in LMLISP and in Common LISP
APPLY is willing to accept the name of the thing in lieu of the thing
(for example, (APPLY 'FOO args) instead of (APPLY #'FOO args)).
However, if you believe in the thing-name distinction, then it is
even more important that ((:PROPERTY FOO BAR) 3 5 :START 7) work
as a function call!  It has the name of the function first, and then
the argument forms.  It is entirely analogous to (FOO 3 5 :START 7).

∂09-Nov-82  0444	Scott E. Fahlman <Fahlman at Cmu-20c> 	Remarks on mini-ballot    
Date: Tuesday, 9 November 1982  07:44-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI, David A. Moon <Moon at SCRC-POINTER at MIT-MC>
Subject: Remarks on mini-ballot


I am really getting scared.  Allowing ((:property foo bar) ...) seems to
me to open up all sorts of evil and hairy possibilities.  I can't name
them right now, but I think they're out there and we should all think
hard before swallowing this.  If this turns out to be an error, it may
be too late to correct it by the time we realize the problem, since
we're going to press fairly soon.  Consistency is OK in its place, but
we shouldn't let it push us around.

-- Scott

∂09-Nov-82  0752	ZVONA at MIT-MC 	function specs    
Date: Tuesday, 9 November 1982  10:49-EST
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: function specs
In-reply-to: The message of 9 Nov 1982 0245-EST () from Guy.Steele at CMU-10A

    However, the analogy above also indicates to me that function specs
    like (:PROPERTY FOO BAR) really are a kind of generalized name for
    a function.  If so, orthogonality demands that they be permissible
    in a lot of places where currently I believe they are not in Lisp Machine
    LISP:
    (a) In FUNCTION:  #'(:PROPERTY FOO BAR) ought to be legal.
    (b) As an argument to APPLY:  (APPLY '(:PROPERTY FOO BAR) args)
    (c) In ordinary function calls!  ((:PROPERTY FOO BAR) 5 7 :START 3 :END 5)

Empirical evidence:

I've seen naive users trying to put function specs in places like these,
and losing, and wondering what they did wrong.

∂09-Nov-82  0803	ZVONA at MIT-MC 	function specs    
Date: Tuesday, 9 November 1982  10:49-EST
Sender: ZVONA at MIT-OZ
From: ZVONA at MIT-MC
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: function specs
In-reply-to: The message of 9 Nov 1982 0245-EST () from Guy.Steele at CMU-10A

    However, the analogy above also indicates to me that function specs
    like (:PROPERTY FOO BAR) really are a kind of generalized name for
    a function.  If so, orthogonality demands that they be permissible
    in a lot of places where currently I believe they are not in Lisp Machine
    LISP:
    (a) In FUNCTION:  #'(:PROPERTY FOO BAR) ought to be legal.
    (b) As an argument to APPLY:  (APPLY '(:PROPERTY FOO BAR) args)
    (c) In ordinary function calls!  ((:PROPERTY FOO BAR) 5 7 :START 3 :END 5)

Empirical evidence:

I've seen naive users trying to put function specs in places like these,
and losing, and wondering what they did wrong.

∂09-Nov-82  1423	Kent M. Pitman <KMP at MIT-MC>
Date: 8 November 1982 20:53-EST
From: Kent M. Pitman <KMP at MIT-MC>
To: Benson at UTAH-20
cc: Common-Lisp at SU-AI

In most current Lisp implementations, one cannot write
 (SETF (GET 'FOO 'BAR) #'(LAMBDA ...))
unless he doesn't mind #'(LAMBDA ...) not being compiled. Toplevel
non-definitional forms are not compiled in Maclisp or LispM, for example.
Hence, without the existence of (DEFUN (:PROPERTY FOO BAR) ...), one
would have to write
   (DEFUN something ...)
   (SETF (GET 'FOO 'BAR) #'something)
which is a bit tedious.

I don't know if Common-Lisp has taken a stand on whether toplevel LAMBDAs
like this one get compiled. Discussion came up about it before. It's related
to the (PROGN 'COMPILE ...) issue and should probably be defined. I'm 
personally in favor of avoiding a (PROGN 'COMPILE ...) primitive
and compiling all toplevel forms. In such case, the SETF you show would be
technically correct, but it lacks the declarative appeal of being integrated
into a DEFUN.

The question, I guess, comes down to whether you think of what you're
doing as defining a function with a complex name or creating an
anonymous function and putting it in a complex place. I think there is
need for both and the two issues should be kept separate.

∂09-Nov-82  1423	Kent M. Pitman <KMP at MIT-MC> 	Mini-ballot  
Date: 8 November 1982 20:54-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  Mini-ballot
To: Guy.Steele at CMU-10A
cc: common-lisp at SU-AI

(1) My experience with LispM function specs leads me to believe that 
    something along these lines is worthwhile. I waver between saying "yes"
    to (c) because I am not firm on the details and it might be better to
    wait and (a) because I know it's a valuable tool and I've seen what 
    happens when you don't have it. With regard to (b), I object rather 
    strongly on the following counts:

     * I would prefer that they be statically analyzable. I can figure out
       at code analysis time (eg, compile time or at the time I'm reading 
       someone else's code) what (DEFUN (GET 'FOO 'BAR) ...) means. And have
       a pretty good idea of what the code is trying to say. But if the
       person does (DEFUN (GET FOO BAR) ...), I can analyze this code only
       formally and have no good feeling for what it's going to do. 
       I think definitional forms should try to stay simple and the programmer
       should write (SETF (GET FOO BAR) #'(LAMBDA ...)) in the few cases 
       where he needs it.

       I would be uncomfortable with special-casing (ie, requiring) QUOTE
       in this kind of form, so restricting things to the (GET 'FOO 'BAR)
       case will not make me feel better.

     * If (DEFUN (GET 'FOO 'BAR) (X) X) means (SETF (GET 'FOO 'BAR)
						    #'(LAMBDA (X) X))
       then (DEFUN F (X) X) should mean (SETF F #'(LAMBDA (X) X)) and
       not (SETF #'F #'(LAMBDA (X) ...)). This incompatibility bothers me.

    I'd like to see a concrete proposal for exactly what LispM style stuff
    we'd put in before I vote for (a) over (c), however.

    A more conservative alternative is to go the Maclisp route and say that
    the useful case of DEFUN'ing properties can be done by
	(DEFUN (sym prop) bvl . body)
    and not go for either the function spec or the SETF approach for now
    until more thinking has been done. This syntax would be fairly easily
    upgraded later if people were encouraged to never use a sym which was
    on the keyword package in such a DEFUN so that later upgrading if desired
    could be done in an upward compatible fashion.
    This is preferable in my mind to HEDRICK's (DEFUN-PROP ...) proposal 
    because it is not as verbose and it is upward compatible in a way that
    doesn't introduce arbitrarily many new operators.

(2) I guess I buy the argument that constants oughtn't have *'s around them.
    Knowing by looking at a thing whether it's intended to be bound is 
    certainly a useful property.

∂09-Nov-82  1603	Eric Benson <BENSON at UTAH-20> 	#'(LAMBDA ...) ==> CODE    
Date:  9 Nov 1982 1700-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: #'(LAMBDA ...) ==> CODE
To: KMP at MIT-MC
cc: Common-Lisp at SU-AI
In-Reply-To: Your message of 8-Nov-82 1853-MST

I believe any occurence of (FUNCTION (LAMBDA ...)) in a file at the top
level should be compiled when the file is compiled.  In fact any
occurences which are created by macroexpansion at the top level should
be compiled as well.  Are these to be called "subrs" or "code objects"
or what?
-------

∂09-Nov-82  1755	David.Dill at CMU-10A (L170DD60) 	mini-ballot
Date:  9 November 1982 2055-EST (Tuesday)
From: David.Dill at CMU-10A (L170DD60)
To: common-lisp at su-ai
Subject: mini-ballot
Message-Id: <09Nov82 205523 DD60@CMU-10A>

1. I am not convinced that the usefulness of SETF-like defun syntax
for putting the things where you want them, or for debugging, justifies
the extra hair and ugliness.  A case could be made that it's sociable
to name your functions if you want it to be easy to debug code that calls
them.  In common lisp, you can even have named lambda expressions
without doing a DEFUN.

2. Since the special declarations generated by DEFVAR are pervasive, it
is relatively easy to bind a special accidentally, thinking that it's a
local variable.  The best solution to this sort of problem, and a lot
of others, would be to distinguish syntactically special bindings and
references from lexical ones.  Otherwise, a special/lexical naming
convention seems like the best thing (e.g. if the variable starts with
an "S", it's special).



∂09-Nov-82  1933	Guy.Steele at CMU-10A 	Named lambdas    
Date:  9 November 1982 2233-EST (Tuesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Named lambdas

In response to DILL's message: actually, NAMED-LAMBDA is not
presently in Common LISP, though Spice LISP does support it.
Should NAMED-LAMBDA be in Common LISP?
--Guy

∂09-Nov-82  2120	Guy.Steele at CMU-10A 	Quick query about CONSTANTP
Date: 10 November 1982 0006-EST (Wednesday)
From: Guy.Steele at CMU-10A
To: common-lisp at SU-AI
Subject: Quick query about CONSTANTP

Sometimes it is useful to know whether a symbol is a constant
(for example, T, NIL, PI, MOST-POSITIVE-FIXNUM, :DIRECTORY, and so on).
How about a function CONSTANTP for this purpose?  (In particular,
the evaluator needs it for error-checking.)  It could be implemented
as a property-list chek, though for speed it would be nice if an
implementation could dig up a bit in the symbol itself.  This bit
would be set by DEFCONSTANT and when interning in the keyword package.
--Guy

∂09-Nov-82  2234	STEELE at CMU-20C 	New proposed evaluators   
Date: 10 Nov 1982 0133-EST
From: STEELE at CMU-20C
Subject: New proposed evaluators
To: common-lisp at SU-AI

There follow improved and corrected versions of the proposed model
evaluators for Common LISP.  Improvements include renaming of
the variable EVALHOOK to *EVALHOOK*, allowing macro calls to
expand into declarations, improved interaction of error handling
and lexical environments (many thanks to KMP), increased use of
speial variables in the second version, and many bug fixes.
---------------------------------------------------------------
;;; This evaluator splits the lexical environment into four
;;; logically distinct entities:
;;;	VENV = lexical variable environment
;;;	FENV = lexical function and macro environment
;;;	BENV = block name environment
;;;	GENV = go tag environment
;;; Each environment is an a-list.  It is never the case that
;;; one can grow and another shrink simultaneously; the four
;;; parts could be united into a single a-list.  The four-part
;;; division saves consing and search time.
;;;
;;; Each entry in VENV has one of two forms: (VAR VALUE) or (VAR).
;;; The first indicates a lexical binding of VAR to VALUE, and the
;;; second indicates a special binding of VAR (implying that the
;;; special value should be used).
;;;
;;; Each entry in FENV looks like (NAME TYPE . FN), where NAME is the
;;; functional name, TYPE is either FUNCTION or MACRO, and FN is the
;;; function or macro-expansion function, respectively.  Entries of
;;; type FUNCTION are made by FLET and LABELS; those of type MACRO
;;; are made by MACROLET.
;;;
;;; Each entry in BENV looks like (NAME), where NAME is the name
;;; of the block.  The cons cell that is the entry is used as a
;;; catch tag for implementing RETURN-FROM.  If the entry has been
;;; clobbered to look like (NAME . INVALID), then the block has
;;; been exited, and a return to that block is an error.
;;;
;;; Each entry in GENV looks like (TAG MARKER . BODY), where TAG is
;;; a go tag, MARKER is a unique cons used as a catch tag, and BODY
;;; is the statement sequence that follows the go tag.  If the car of
;;; MARKER, normally NIL, has been clobbered to be INVALID, then
;;; the tag body has been exited, and a GO to that tag is an error.

;;; An interpreted-lexical-closure contains a function (normally a
;;; lambda-expression) and the lexical environment.

(defstruct interpreted-lexical-closure function venv fenv benv genv)


;;; The EVALHOOK feature allows a user-supplied function to be called
;;; whenever a form is to be evaluated.  The presence of the lexical
;;; environment requires an extension of the feature as it is defined
;;; in MacLISP.  Here, the user hook function must accept not only
;;; the form to be evaluated, but also the components of the lexical
;;; environment; these must then be passed verbatim to EVALHOOK or
;;; *EVAL in order to perform the evaluation of the form correctly.
;;; The precise number of components should perhaps be allowed to be
;;; implementation-dependent, so it is probably best to require the
;;; user hook function to accept arguments as (FORM &REST ENV) and
;;; then to perform evaluation by (APPLY #'EVALHOOK FORM HOOKFN ENV),
;;; for example.

(defvar *evalhook* nil)

(defun evalhook (exp hookfn venv fenv benv genv)
  (let ((*evalhook* hookfn)) (%eval exp venv fenv benv genv)))

(defun eval (exp)
  (*eval exp nil nil nil nil))

;;; *EVAL looks useless here, but does more complex things
;;; in alternative implementations of this evaluator.

(defun *eval (exp venv fenv benv genv)
  (%eval exp venv fenv benv genv))
!
;;; Function names beginning with "%" are intended to be internal
;;; and not defined in the Common LISP white pages.

;;; %EVAL is the main evaluation function.

(defun %eval (exp venv fenv benv genv)
  (if *evalhook*
      (let ((hookfn *evalhook*) (*evalhook* nil))
	(funcall hookfn exp venv fenv benv genv))
      (typecase exp
	;; A symbol is first looked up in the lexical variable environment.
	(symbol (let ((slot (assq exp venv)))
		  (cond ((and slot (not (null (cdr slot))))
			 (cadr slot))
			((boundp exp) (symbol-value exp))
			(t (cerror :unbound-variable
				   "The symbol ~S has no value"
				   exp)))))
	;; Numbers, strings, bit-vectors, and characters self-evaluate.
	((or number string bit-vector character) exp)
	;; Conses require elaborate treatment based on the car.
	(cons (typecase (car exp)
		;; A symbol is first looked up in the lexical function environment.
		;; This lookup is cheap if the environment is empty, a common case.
		(symbol
		 (let ((fn (car exp)))
		   (loop (let ((slot (assq fn fenv)))
			   (unless (null slot)
			     (return (case (cadr slot)
				       (macro (%eval (%macroexpand
						      (cddr slot)
						      (if (eq fn (car exp))
							  exp
							  (cons fn (cdr exp))))))
				       (function (%apply (cddr slot)
							 (%evlis (cdr exp) venv fenv benv genv)
							 venv fenv benv genv))
				       (t <implementation-error>)))))
			 ;; If not in lexical function environment,
			 ;;  try the definition cell of the symbol.
			 (when (fboundp fn)
			   (return (cond ((special-form-p fn)
					  (%invoke-special-form
					   fn (cdr exp) venv fenv benv genv))
					 ((macro-p fn)
					  (%eval (%macroexpand
						  (get-macro-function (symbol-function fn))
						  (if (eq fn (car exp))
						      exp
						      (cons fn (cdr exp))))
						 venv fenv benv genv))
					 (t (%apply (symbol-function fn)
						    (%evlis (cdr exp) venv fenv benv genv)
						    venv fenv benv genv)))))
			 (setq fn
			       (cerror :undefined-function
				       "The symbol ~S has no function definition"
				       fn))
			 (unless (symbolp fn)
			   (return (%apply fn
					   (%evlis (cdr exp) venv fenv benv genv)
					   venv fenv benv genv))))))
		;; A cons in function position must be a lambda-expression.
		;; Note that the construction of a lexical closure is avoided here.
		(cons (%apply (car exp)
			      (%evlis (cdr exp) venv fenv benv genv)
			      venv fenv benv genv))
		(t (%eval (cerror :invalid-form
				  "Cannot evaluate the form ~S: function position has invalid type ~S"
				  exp (type-of (car exp)))
			  venv fenv benv genv))))
	(t (%eval (cerror :invalid-form
			  "Cannot evaluate the form ~S: invalid type ~S"
			  exp (type-of exp))
		  venv fenv benv genv)))))
!
;;; Given a list of forms, evaluate each and return a list of results.

(defun %evlis (forms venv fenv benv genv)
  (mapcar #'(lambda (form) (%eval form venv fenv benv genv)) forms))

;;; Given a list of forms, evaluate each, discarding the results of
;;; all but the last, and returning all results from the last.

(defun %evprogn (body venv fenv benv genv)
  (if (endp body) nil
      (do ((b body (cdr b)))
	  ((endp (cdr b))
	   (%eval (car b) venv fenv benv genv))
	(%eval (car b) venv fenv benv genv))))

;;; APPLY takes a function, a number of single arguments, and finally
;;; a list of all remaining arguments.  The following song and dance
;;; attempts to construct efficiently a list of all the arguments.

(defun apply (fn firstarg &rest args*)
  (%apply fn
	  (cond ((null args*) firstarg)
		((null (cdr args*)) (cons firstarg (car args*)))
		(t (do ((x args* (cdr x))
			(z (cddr args*) (cdr z)))
		       ((null z)
			(rplacd x (cadr x))
			(cons firstarg (car args*))))))
	  nil nil nil nil))
!
;;; %APPLY does the real work of applying a function to a list of arguments.
;;; The environment is passed in because it leads to more natural error
;;; recovery.

(defun %apply (fn args venv fenv benv genv)
  (typecase fn
    ;; For a compiled function, an implementation-dependent "spread"
    ;;  operation and invocation is required.
    (compiled-function (%invoke-compiled-function fn args))
    ;; The same goes for a compiled closure over lexical variables.
    (compiled-lexical-closure (%invoke-compiled-lexical-closure fn args))
    ;; The treatment of interpreted lexical closures is elucidated fully here.
    (interpreted-lexical-closure
     (%lambda-apply (interpreted-lexical-closure-function fn)
		    args
		    (interpreted-lexical-closure-venv fn)
		    (interpreted-lexical-closure-fenv fn)
		    (interpreted-lexical-closure-benv fn)
		    (interpreted-lexical-closure-genv fn)))
    ;; For a symbol, the function definition is used, if it is a function.
    (symbol (%apply (cond ((not (fboundp fn))
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
			  ((special-form-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a special form"
				   fn))
			  ((macro-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a macro"
				   fn))
			  (t (symbol-function fn)))
		    args venv fenv benv genv))
    (cons (if (eq (car fn) 'lambda)
	      (%lambda-apply fn args venv fenv benv genv)
	      (%apply (cerror :invalid-function
			      "~S is not a valid function"
			      fn)
		      args venv fenv benv genv)))
    (t (%apply (cerror :invalid function
		       "~S has an invalid type ~S for a function"
		       fn (type-of fn))
	       args venv fenv benv genv))))
!
;;; %LAMBDA-APPLY is the hairy part, that takes care of applying
;;; a lambda-expression in a given lexical environment to given
;;; arguments.  The complexity arises primarily from the processing
;;; of the parameter list.
;;;
;;; If at any point the lambda-expression is found to be malformed
;;; (typically because of an invalid parameter list), or if the list
;;; of arguments is not suitable for the lambda-expression, a correctable
;;; error is signalled; correction causes a throw to be performed to
;;; the tag %LAMBDA-APPLY-RETRY, passing back a (possibly new)
;;; lambda-expression and a (possibly new) list of arguments.
;;; The application is then retried.  If the new lambda-expression
;;; is not really a lambda-expression, then %APPLY is used instead of
;;; %LAMBDA-APPLY.
;;;
;;; In this evaluator, PROGV is used to instantiate variable bindings
;;; (though its use is embedded with a macro called %BIND-VAR).
;;; The throw that precedes a retry will cause special bindings to
;;; be popped before the retry.

(defun %lambda-apply (lexp args venv fenv benv genv)
  (multiple-value-bind (newfn newargs)
		       (catch '%lambda-apply-retry
			 (return-from %lambda-apply
			   (%lambda-apply-1 lexp args venv fenv benv genv)))
    (if (and (consp lexp) (eq (car lexp) 'lambda))
	(%lambda-apply newfn newargs venv fenv benv genv)
	(%apply newfn newargs venv fenv benv genv))))

;;; Calling this function will unwind all special variables
;;; and cause FN to be applied to ARGS in the original lexical
;;; and dynamic environment in force when %LAMBDA-APPLY was called.

(defun %lambda-apply-retry (fn args)
  (throw '%lambda-apply-retry (values fn args)))

;;; This function is convenient when the lambda expression is found
;;; to be malformed.  REASON should be a string explaining the problem.

(defun %bad-lambda-exp (lexp oldargs reason)
  (%lambda-apply-retry
   (cerror :invalid-function
	   "Improperly formed lambda-expression ~S: ~A"
	   lexp reason)
   oldargs))

;;; (%BIND-VAR VAR VALUE . BODY) evaluates VAR to produce a symbol name
;;; and VALUE to produce a value.  If VAR is determined to have been
;;; declared special (as indicated by the current binding of the variable
;;; SPECIALS, which should be a list of symbols, or by a SPECIAL property),
;;; then a special binding is established using PROGV.  Otherwise an
;;; entry is pushed onto the a-list presumed to be in the variable VENV.

;;; The CONSTANTP test ideally is true for any constant symbol;
;;; it should at least check for T, NIL, and keywords.

(defmacro %bind-var (var value &body body)
  (let ((xvar (gensym)) (xvalue (gensym)))
    `(let ((,xvar ,var) (,xvalue ,value))
       (loop (when (not (constantp ,xvar)) (return))
	     (setq ,xvar (cerror :invalid-variable
				 "~S is a constant and may not be bound"
				 ,xvar)))
       (let ((specp (or (memq ,xvar specials) (get ,xvar 'special))))
	 (progv (and specp (list ,xvar)) (and specp (list ,xvalue))
		(push (if specp (list ,xvar) (list ,xvar ,xvalue)) venv)
		,@body)))))

;;; %LAMBDA-KEYWORD-P is true iff X (which must be a symbol)
;;; has a name beginning with an ampersand.

(defun %lambda-keyword-p (x)
  (char= #\& (char 0 (symbol-pname x))))
!
;;; %LAMBDA-APPLY-1 is responsible for verifying that LEXP is
;;; a lambda-expression, for extracting a list of all variables
;;; declared SPECIAL in DECLARE forms, and for finding the
;;; body that follows any DECLARE forms.

(defun %lambda-apply-1 (lexp args venv fenv benv genv)
  (cond ((or (not (consp lexp))
	     (not (eq (car lexp) 'lambda))
	     (atom (cdr lexp))
	     (not (listp (cadr lexp))))
	 (%bad-lambda-exp lexp args "improper lambda-expression"))
	(t (do ((body (cddr lexp) (cdr body))
		(specials '()))
	       ((or (endp body) (not (consp (car body))))
		(%bind-required lexp args (cadr lexp) fenv benv genv venv args specials nil body))
	     (let ((form (macroexpand (car body))))
	       (cond ((or (not (consp form))
			  (not (eq (car form) 'declare)))
		      (return (%bind-required lexp args (cadr lexp) fenv benv genv venv args specials form body)))
		     (t (dolist (decl (cdar form))
			  (when (eq (car decl) 'special)
			    (setq specials
				  (if (null specials)	;Avoid consing
				      (cdar decl)
				      (append (cdar decl) specials))))))))))))

;;; %BIND-REQUIRED handles the pairing of arguments to required parameters.
;;; Error checking is performed for too few or too many arguments.
;;; If a lambda-list keyword is found, %TRY-OPTIONAL is called.
;;; Here, as elsewhere, if the binding process terminates satisfactorily
;;; then the body is evaluated using %EVPROGN in the newly constructed
;;; dynamic and lexical environment.

(defun %bind-required (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn form body venv fenv benv genv)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  lexp oldargs))))
	((not (symbolp (car varlist)))
	 (%bad-lambda-exp lexp oldargs "required parameter name not a symbol"))
	((%lambda-keyword-p (car varlist))
	 (%try-optional lexp oldargs varlist venv fenv benv genv args specials form body))
	((null args)
	 (%lambda-apply-retry lexp 
			      (cerror :too-few-arguments
				      "Too few arguments for function ~S: ~S"
				      lexp oldargs)))
	(t (%varbind (car varlist) (car args)
		      (%bind-required lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body)))))
!
;;; %TRY-OPTIONAL determines whether the lambda-list keyword &OPTIONAL
;;; has been found.  If so, optional parameters are processed; if not,
;;; the buck is passed to %TRY-REST.

(defun %try-optional (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&optional)
	 (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
	(t (%try-rest lexp oldargs varlist venv fenv benv genv args specials form body))))

;;; %BIND-OPTIONAL determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-optional (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn form body venv fenv benv genv)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  lexp oldargs))))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%try-rest lexp oldargs varlist venv fenv benv genv args specials form body)
			(%process-optional lexp oldargs varlist venv fenv benv
					   genv args specials form body varspec nil nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-optional lexp oldargs varlist venv fenv benv
				       genv args specials form body
				       (car varspec)
				       (cadr varspec)
				       (caddr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed optional parameter specifier")))))))

;;; %PROCESS-OPTIONAL takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-optional (lexp oldargs varlist venv fenv benv genv args specials form body var init varp)
  (let ((value (if (null args) (%eval init venv fenv benv genv) (car args))))
    (%varbind var value
      (if varp
	  (%varbind varp (not (null args))
	    (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body))
	  (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body)))))
!
;;; %TRY-REST determines whether the lambda-list keyword &REST
;;; has been found.  If so, the rest parameter is processed;
;;; if not, the buck is passed to %TRY-KEY, after a check for
;;; too many arguments.

(defun %try-rest (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&rest)
	 (%bind-rest lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
	((and (not (eq (car varlist) '&key))
	      (not (null args)))
	 (%lambda-apply-retry lexp
			      (cerror :too-many-arguments
				      "Too many arguments for function ~S: ~S"
				      lexp oldargs)))
	(t (%try-key lexp oldargs varlist venv fenv benv genv args specials form body))))

;;; %BIND-REST ensures that there is a parameter specifier for
;;; the &REST parameter, binds it, and then evaluates the body or
;;; calls %TRY-KEY.

(defun %bind-rest (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((or (endp varlist)
	     (not (symbolp (car varlist))))
	 (%bad-lambda-exp lexp oldargs "missing rest parameter specifier"))
	(t (%varbind (car varlist) args
	     (cond ((endp (cdr varlist))
		    (%lambda-evprogn form body venv fenv benv genv))
		   ((and (symbolp (cadr varlist))
			 (%lambda-keyword-p (cadr varlist)))
		    (%try-key lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
		   (t (%bad-lambda-exp lexp oldargs "malformed after rest parameter specifier")))))))
!
;;; %TRY-KEY determines whether the lambda-list keyword &KEY
;;; has been found.  If so, keyword parameters are processed;
;;; if not, the buck is passed to %TRY-AUX.

(defun %try-key (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&key)
	 (%bind-key lexp oldargs (cdr varlist) venv fenv benv genv args specials form body nil))
	(t (%try-aux lexp oldargs varlist venv fenv benv genv specials form body))))

;;; %BIND-KEY determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-key (lexp oldargs varlist venv fenv benv genv args specials form body keys)
  (cond ((endp varlist)
	 (%check-for-bad-keywords lexp args keys)
	 (%lambda-evprogn form body venv fenv benv genv))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(cond ((not (eq varspec '&allow-other-keywords))
			       (%check-for-bad-keywords lexp args keys)
			       (%try-aux lexp oldargs varlist venv fenv benv genv specials form body))
			      ((endp (cdr varlist))
			       (%lambda-evprogn form body venv fenv benv genv))
			      ((%lambda-keyword-p (cadr varlist))
			       (%try-aux lexp oldargs (cdr varlist) venv fenv benv genv specials form body))
			      (t (%bad-lambda-exp lexp oldargs "invalid after &ALLOW-OTHER-KEYWORDS")))
			(%process-key lexp oldargs varlist venv fenv benv
				      genv args specials form body keys
				      (intern (symbol-print-name varspec) keyword-package)
				      varspec nil nil)))
		   ((and (consp varspec)
			 (or (symbolp (car varspec))
			     (and (consp (car varspec))
				  (consp (cdar varspec))
				  (symbolp (cadar varspec))
				  (endp (cddar varspec))))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-key lexp oldargs varlist venv fenv benv
				  genv args specials form body keys
				  (if (consp (car varspec))
				      (caar varspec)
				      (intern (symbol-print-name (car varspec)) keyword-package))
				  (if (consp (car varspec))
				      (cadar varspec)
				      (car varspec))
				  (cadr varspec)
				  (caddr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed keyword parameter specifier")))))))

;;; Optional error check for bad keyword arguments.

(defun %check-for-bad-keywords (lexp args keys)
  (do ((a args (cddr a)))
      ((endp args))
    (unless (memq (car a) keys)
      (cerror :unexpected-keyword
	      "Keyword not expected by function ~S: ~S"
	      lexp (car a)))))

;;; %PROCESS-KEY takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-key (lexp oldargs varlist venv fenv benv genv args specials form body keys kwd var init varp)
  (do ((a args (cddr a)))
      ((endp a)
       (%process-key-1 lexp oldargs varlist venv fenv benv genv args specials
		       form body keys kwd var init varp
		       (%eval init venv fenv benv genv) nil))
    (when (eq (car a) kwd)
      (return (%process-key-1 lexp oldargs varlist venv fenv benv genv args specials
			      form body keys kwd var init varp
			      (cadr a) t)))))

(defun %process-key-1 (lexp oldargs varlist venv fenv benv genv args specials form body keys kwd var init varp value suppliedp)
  (%varbind var value
    (if varp
	(%varbind varp suppliedp
	  (%bind-key lexp oldargs varlist venv fenv benv genv args specials form body (cons kwd keys)))
	(%bind-key lexp oldargs varlist venv fenv benv genv args specials form body (cons kwd keys)))))
!
;;; %TRY-AUX determines whether the keyword &AUX
;;; has been found.  If so, auxiliary variables are processed;
;;; if not, an error is signalled.

(defun %try-aux (lexp oldargs varlist venv fenv benv genv specials form body)
  (cond ((eq (car varlist) '&aux)
	 (%bind-aux lexp oldargs (cdr varlist) venv fenv benv genv specials form body))
	(t (%bad-lambda-exp lexp oldargs "unknown or misplaced lambda-list keyword"))))

;;; %BIND-AUX determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-aux (lexp oldargs varlist venv fenv benv genv specials form body)
  (cond ((endp varlist)
	 (%lambda-evprogn form body venv fenv benv genv))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%bad-lambda-exp lexp oldargs "unknown or misplaced lambda-list keyword")
			(%process-aux lexp oldargs varlist venv fenv benv
				      genv specials form body varspec nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (endp (cddr varspec)))
		    (%process-aux lexp oldargs varlist venv fenv benv
				       genv specials form body
				       (car varspec)
				       (cadr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed aux variable specifier")))))))

;;; %PROCESS-AUX takes care of binding the auxiliary variable.

(defun %process-aux (lexp oldargs varlist venv fenv benv genv specials form body var init)
  (%varbind var (and init (%eval init venv fenv benv genv))
    (%bind-aux lexp oldargs varlist venv fenv benv genv specials form body)))

(defun %lambda-evprogn (form body venv fenv benv genv)
  (unless (null form) (%eval form venv fenv benv genv))
  (%evprogn body venv fenv benv genv))
!
;;; Definitions for various special forms and macros.

(defspec quote (obj) (venv fenv benv genv) obj)

(defspec function (fn) (venv fenv benv genv)
  (loop (cond ((consp fn)
	       (cond ((eq (car fn) 'lambda)
		      (return (make-interpreted-closure :function fn
							:venv venv
							:fenv fenv
							:benv benv
							:genv genv)))
		     (t (setq fn (cerror :invalid-function
					 "~S is not a valid argument for FUNCTION"
					 fn)))))
	      ((symbolp fn)
	       (let ((slot (assq fn fenv)))
		 (cond (slot
			(case (cadr slot)
			  (macro (setq fn (cerror :invalid-function
						  "The name ~S is invalid for FUNCTION: it names a macro"
						  fn)))
			  (function (return (cddr slot)))
			  (t <implementation-error>)))
		       ((fboundp fn)
			(cond ((special-form-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a special form"
						fn)))
			      ((macro-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a macro"
						fn)))
			      (t (setq fn (symbol-function fn)))))
		       (t (setq fn (cerror :invalid-function
					   "The symbol ~S has no function definition"
					   fn))))))
	      (t (setq fn (cerror :invalid-function
				  "~S is not a valid argument for FUNCTION"
				  fn))))))

(defspec if (pred con &optional alt) (venv fenv benv genv)
  (if (%eval pred venv fenv benv genv)
      (%eval con venv fenv benv genv)
      (%eval alt venv fenv benv genv)))

;;; The BLOCK construct provides a PROGN with a named contour around it.
;;; It is interpreted by first putting an entry onto BENV, consisting
;;; of a 1-list of the name.  This list cell serves as a catch tag.
;;; Then the body is executed.
;;; If a RETURN-FROM is interpreted, a throw occurs.  If the BLOCK
;;; construct is exited for any reason (including falling off the end, which
;;; returns the results of evaluating the last form in the body), the cdr of
;;; the entry is clobbered to be INVALID, to indicate that that particular
;;; entry is no longer valid for RETURN-FROM.

(defspec block (name &body body) (venv fenv benv genv)
  (let ((slot (list name)))
    (unwind-protect (catch slot
		      (%evprogn body venv fenv (cons slot benv) genv))
		    (rplacd slot 'invalid))))

(defspec return (form) (venv fenv benv genv)
  (let ((slot (assq nil benv)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form venv fenv benv genv))))))

(defspec return-from (name form) (venv fenv benv genv)
  (let ((slot (assq name benv)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form venv fenv benv genv))))))
!
(defmacro prog (vars &rest body)
  (do ((b body (cdr b))
       (decls '() (cons (car b) decls)))
      ((or (endp b)
	   (atom (car b))
	   (not (eq (caar b) 'declare)))
       `(let ,vars ,@(nreverse decls) (block nil (tagbody ,@b))))))

;;; The TAGBODY construct provides a body with GO tags in it.
;;; It is interpreted by first putting one entry onto GENV for
;;; every tag in the body; doing this ahead of time saves searching
;;; at GO time.  A unique cons whose car is NIL is constructed for
;;; use as a unique catch tag.  Then the body is executed.
;;; If a GO is interpreted, a throw occurs, sending as the thrown
;;; value the point in the body after the relevant tag.
;;; If the TAGBODY construct is exited for any reason (including
;;; falling off the end, which produces the value NIL), the car of
;;; the unique marker is clobbered to be INVALID, to indicate that
;;; tags associated with that marker are no longer valid.

(defspec tagbody (&rest body) (venv fenv benv genv)
  (do ((b body (cdr b))
       (marker (list nil)))
      ((endp p)
       (block exit
	 (unwind-protect
	  (loop (setq body
		      (catch marker
			(do ((b body (cdr b)))
			    ((endp b) (return-from exit nil))
			  (unless (atom (car b))
			    (%eval (car b) venv fenv benv genv))))))
	  (rplaca marker 'invalid))))
    (when (atom (car b))
      (push (list* (car b) marker (cdr b)) genv))))

(defspec go (tag) (venv fenv benv genv)
  (let ((slot (assq tag genv)))
    (cond ((null slot) (ferror ???<unseen-go-tag>))
	  ((eq (caadr slot) 'invalid) (ferror ???<go-tag-no-longer-valid>))
	  (t (throw (cadr slot) (cddr slot))))))
---------------------------------------------------------------
;;; This version uses some special variables to avoid passing stuff around.

;;; This evaluator splits the lexical environment into four
;;; logically distinct entities:
;;;	VENV = lexical variable environment
;;;	FENV = lexical function and macro environment
;;;	BENV = block name environment
;;;	GENV = go tag environment
;;; Each environment is an a-list.  It is never the case that
;;; one can grow and another shrink simultaneously; the four
;;; parts could be united into a single a-list.  The four-part
;;; division saves consing and search time.
;;;
;;; In this implementation, the four environment parts are normally
;;; kept in four special variables %VENV%, %FENV%, %BENV%, and %GENV%.
;;; (These are internal to the implementation, and are not meant to
;;; be user-accessible.)

(defvar %venv% nil)
(defvar %fenv% nil)
(defvar %benv% nil)
(defvar %genv% nil)

;;; Each entry in VENV has one of two forms: (VAR VALUE) or (VAR).
;;; The first indicates a lexical binding of VAR to VALUE, and the
;;; second indicates a special binding of VAR (implying that the
;;; special value should be used).
;;;
;;; Each entry in FENV looks like (NAME TYPE . FN), where NAME is the
;;; functional name, TYPE is either FUNCTION or MACRO, and FN is the
;;; function or macro-expansion function, respectively.  Entries of
;;; type FUNCTION are made by FLET and LABELS; those of type MACRO
;;; are made by MACROLET.
;;;
;;; Each entry in BENV looks like (NAME), where NAME is the name
;;; of the block.  The cons cell that is the entry is used as a
;;; catch tag for implementing RETURN-FROM.  If the entry has been
;;; clobbered to look like (NAME . INVALID), then the block has
;;; been exited, and a return to that block is an error.
;;;
;;; Each entry in GENV looks like (TAG MARKER . BODY), where TAG is
;;; a go tag, MARKER is a unique cons used as a catch tag, and BODY
;;; is the statement sequence that follows the go tag.  If the car of
;;; MARKER, normally NIL, has been clobbered to be INVALID, then
;;; the tag body has been exited, and a go to that tag is an error.

;;; An interpreted-lexical-closure contains a function (normally a
;;; lambda-expression) and the lexical environment.

(defstruct interpreted-lexical-closure function venv fenv benv genv)


;;; The EVALHOOK feature allows a user-supplied function to be called
;;; whenever a form is to be evaluated.  The presence of the lexical
;;; environment requires an extension of the feature as it is defined
;;; in MacLISP.  Here, the user hook function must accept not only
;;; the form to be evaluated, but also the components of the lexical
;;; environment; these must then be passed verbatim to EVALHOOK or
;;; *EVAL in order to perform the evaluation of the form correctly.
;;; The precise number of components should perhaps be allowed to be
;;; implementation-dependent, so it is probably best to require the
;;; user hook function to accept arguments as (FORM &REST ENV) and
;;; then to perform evaluation by (APPLY #'EVALHOOK FORM HOOKFN ENV),
;;; for example.

(defvar *evalhook* nil)

(defun evalhook (exp hookfn %venv% %fenv% %benv% %genv%)
  (let ((*evalhook* hookfn))
	(%eval exp)))

(defun eval (exp)
  (*eval exp nil nil nil nil))

(defun *eval (exp %venv% %fenv% %benv% %genv%)
  (%eval exp))
!
;;; Function names beginning with "%" are intended to be internal
;;; and not defined in the Common LISP white pages.

;;; %EVAL is the main evaluation function.  It evaluates EXP in
;;; the current lexical environment, assumed to be in %VENV%, etc.

(defun %eval (exp)
  (if *evalhook*
      (let ((hookfn *evalhook*) (*evalhook* nil))
	(funcall hookfn exp %venv% %fenv% %benv% %genv%))
      (typecase exp
	;; A symbol is first looked up in the lexical variable environment.
	(symbol (let ((slot (assq exp %venv%)))
		  (cond ((and slot (not (null (cdr slot))))
			 (cadr slot))
			((boundp exp) (symbol-value exp))
			(t (cerror :unbound-variable
				   "The symbol ~S has no value"
				   exp)))))
	;; Numbers, strings, bit-vectors, and characters self-evaluate.
	((or number string bit-vector character) exp)
	;; Conses require elaborate treatment based on the car.
	(cons (typecase (car exp)
		;; A symbol is first looked up in the lexical function environment.
		;; This lookup is cheap if the environment is empty, a common case.
		(symbol
		 (let ((fn (car exp)))
		   (loop (let ((slot (assq fn %fenv%)))
			   (unless (null slot)
			     (return (case (cadr slot)
				       (macro (%eval (%macroexpand
						      (cddr slot)
						      (if (eq fn (car exp))
							  exp
							  (cons fn (cdr exp))))))
				       (function (%apply (cddr slot)
							 (%evlis (cdr exp))))
				       (t <implementation-error>)))))
			 ;; If not in lexical function environment,
			 ;;  try the definition cell of the symbol.
			 (when (fboundp fn)
			   (return (cond ((special-form-p fn)
					  (%invoke-special-form fn (cdr exp)))
					 ((macro-p fn)
					  (%eval (%macroexpand
						  (get-macro-function (symbol-function fn))
						  (if (eq fn (car exp))
						      exp
						      (cons fn (cdr exp))))))
					 (t (%apply (symbol-function fn)
						    (%evlis (cdr exp)))))))
			 (setq fn
			       (cerror :undefined-function
				       "The symbol ~S has no function definition"
				       fn))
			 (unless (symbolp fn)
			   (return (%apply fn (%evlis (cdr exp))))))))
		;; A cons in function position must be a lambda-expression.
		;; Note that the construction of a lexical closure is avoided here.
		(cons (apply (car exp) (%evlis (cdr exp))))
		(t (%eval (cerror :invalid-form
				  "Cannot evaluate the form ~S: function position has invalid type ~S"
				  exp (type-of (car exp)))))))
	(t (%eval (cerror :invalid-form
			  "Cannot evaluate the form ~S: invalid type ~S"
			  exp (type-of exp)))))))
!
;;; Given a list of forms, evaluate each and return a list of results.

(defun %evlis (forms)
  (mapcar #'(lambda (form) (%eval form)) forms))

;;; Given a list of forms, evaluate each, discarding the results of
;;; all but the last, and returning all results from the last.

(defun %evprogn (body)
  (if (endp body) nil
      (do ((b body (cdr b)))
	  ((endp (cdr b))
	   (%eval (car b)))
	(%eval (car b)))))

;;; APPLY takes a function, a number of single arguments, and finally
;;; a list of all remaining arguments.  The following song and dance
;;; attempts to construct efficiently a list of all the arguments.

(defun apply (fn firstarg &rest args*)
  (let ((%venv% nil) (%fenv% nil) (%benv% nil) (%genv% nil))
    (%apply fn
	    (cond ((null args*) firstarg)
		  ((null (cdr args*)) (cons firstarg (car args*)))
		  (t (do ((x args* (cdr x))
			  (z (cddr args*) (cdr z)))
			 ((null z)
			  (rplacd x (cadr x))
			  (cons firstarg (car args*)))))))))
!
;;; %APPLY does the real work of applying a function to a list of arguments.

(defun %apply (fn args)
  (typecase fn
    ;; For a compiled function, an implementation-dependent "spread"
    ;;  operation and invocation is required.
    (compiled-function (%invoke-compiled-function fn args))
    ;; The same goes for a compiled closure over lexical variables.
    (compiled-lexical-closure (%invoke-compiled-lexical-closure fn args))
    ;; The treatment of interpreted lexical closures is elucidated fully here.
    (interpreted-lexical-closure
     (let ((%venv% (interpreted-lexical-closure-venv fn))
	   (%fenv% (interpreted-lexical-closure-fenv fn))
	   (%benv% (interpreted-lexical-closure-benv fn))
	   (%genv% (interpreted-lexical-closure-genv fn)))
       (%lambda-apply (interpreted-lexical-closure-function fn) args)))
    ;; For a symbol, the function definition is used, if it is a function.
    (symbol (%apply (cond ((not (fboundp fn))
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
			  ((special-form-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a special form"
				   fn))
			  ((macro-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a macro"
				   fn))
			  (t (symbol-function fn)))
		    args))
    (cons (if (eq (car fn) 'lambda)
	      (%lambda-apply fn args)
	      (%apply (cerror :invalid-function
			      "~S is not a valid function"
			      fn)
		      args)))
    (t (%apply (cerror :invalid function
		       "~S has an invalid type ~S for a function"
		       fn (type-of fn))
	       args))))
!
;;; %LAMBDA-APPLY is the hairy part, that takes care of applying
;;; a lambda-expression in a given lexical environment to given
;;; arguments.  The complexity arises primarily from the processing
;;; of the parameter list.
;;;
;;; If at any point the lambda-expression is found to be malformed
;;; (typically because of an invalid parameter list), or if the list
;;; of arguments is not suitable for the lambda-expression, a correctable
;;; error is signalled; correction causes a throw to be performed to
;;; the tag %LAMBDA-APPLY-RETRY, passing back a (possibly new)
;;; lambda-expression and a (possibly new) list of arguments.
;;; The application is then retried.  If the new lambda-expression
;;; is not really a lambda-expression, then %APPLY is used instead of
;;; %LAMBDA-APPLY.
;;;
;;; In this evaluator, PROGV is used to instantiate variable bindings
;;; (though its use is embedded with a macro called %varbind).
;;; The throw that precedes a retry will cause special bindings to
;;; be popped before the retry.

(defun %lambda-apply (lexp args)
  (multiple-value-bind (newfn newargs)
		       (catch '%lambda-apply-retry
			 (return-from %lambda-apply
			   (let ((%venv% %venv%))
			     (%lambda-apply-1 lexp args))))
    (if (and (consp lexp) (eq (car lexp) 'lambda))
	(%lambda-apply newfn newargs)
	(%apply newfn newargs))))

;;; Calling this function will unwind all special variables
;;; and cause FN to be applied to ARGS in the original lexical
;;; and dynamic environment in force when %LAMBDA-APPLY was called.

(defun %lambda-apply-retry (fn args)
  (throw '%lambda-apply-retry (values fn args)))

(defvar %lexp%)
(defvar %oldargs%)

;;; This function is convenient when the lambda expression is found
;;; to be malformed.  REASON should be a string explaining the problem.

(defun %bad-lambda-exp (reason)
  (%lambda-apply-retry
   (cerror :invalid-function
	   "Improperly formed lambda-expression ~S: ~A"
	   %lexp% reason)
   %oldargs%))

;;; (%varbind VAR VALUE . BODY) evaluates VAR to produce a symbol name
;;; and VALUE to produce a value.  If VAR is determined to have been
;;; declared special (as indicated by the current binding of the variable
;;; SPECIALS, which should be a list of symbols, or by a SPECIAL property),
;;; then a special binding is established using PROGV.  Otherwise an
;;; entry is pushed onto the a-list presumed to be in the variable VENV.

;;; The CONSTANTP test ideally is true for any constant symbol;
;;; it should at least check for T, NIL, and keywords.

(defmacro %varbind (var value &body body)
  (let ((xvar (gensym)) (xvalue (gensym)))
    `(let ((,xvar ,var) (,xvalue ,value))
       (loop (when (not (constantp ,xvar)) (return))
	     (setq ,xvar (cerror :invalid-variable
				 "~S is a constant and may not be bound"
				 ,xvar)))
       (let ((specp (or (memq ,xvar %specials%) (get ,xvar 'special))))
	 (progv (and specp (list ,xvar)) (and specp (list ,xvalue))
		(push (if specp (list ,xvar) (list ,xvar ,xvalue)) venv)
		,@body)))))

;;; %LAMBDA-KEYWORD-P is true iff X (which must be a symbol)
;;; has a name beginning with an ampersand.

(defun %lambda-keyword-p (x)
  (char= #\& (char 0 (symbol-pname x))))
!
;;; %LAMBDA-APPLY-1 is responsible for verifying that LEXP is
;;; a lambda-expression, for extracting a list of all variables
;;; declared SPECIAL in DECLARE forms, and for finding the
;;; body that follows any DECLARE forms.

(defvar %specials%)
(defvar %form%)
(defvar %body%)

(defun %lambda-apply-1 (%lexp% %oldargs%)
  (cond ((or (not (consp %lexp%))
	     (not (eq (car %lexp%) 'lambda))
	     (atom (cdr %lexp%))
	     (not (listp (cadr %lexp%))))
	 (%bad-lambda-exp "improper lambda-expression"))
	(t (do ((%body% (cddr %lexp%) (cdr %body%))
		(%specials% '()))
	       ((or (endp %body%)
		    (not (listp (car %body%))))
		(let ((%form% nil))
		  (%bind-required (cadr %lexp%) %oldargs%)))
	     (let ((%form% (macroexpand (car %body%))))
	       (cond ((or (not (consp %form%))
			  (not (eq (car %form%) 'declare)))
		      (return (%bind-required (cadr %lexp%) %oldargs%)))
		     (t (dolist (decl (cdr %form%))
			  (when (eq (car decl) 'special)
			    (setq %specials%
				  (if (null %specials%)	;Avoid consing
				      (cdar decl)
				      (append (cdar decl) %specials%))))))))))))

;;; %BIND-REQUIRED handles the pairing of arguments to required parameters.
;;; Error checking is performed for too few or too many arguments.
;;; If a lambda-list keyword is found, %TRY-OPTIONAL is called.
;;; Here, as elsewhere, if the binding process terminates satisfactorily
;;; then the body is evaluated using %EVPROGN in the newly constructed
;;; dynamic and lexical environment.

(defun %bind-required (varlist args)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn%)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  %lexp% %oldargs%))))
	((not (symbolp (car varlist)))
	 (%bad-lambda-exp "required parameter name not a symbol"))
	((%lambda-keyword-p (car varlist))
	 (%try-optional varlist args))
	((null args)
	 (%lambda-apply-retry lexp 
			      (cerror :too-few-arguments
				      "Too few arguments for function ~S: ~S"
				      %lexp% %oldargs%)))
	  (t (%varbind (car varlist) (car args)
			(%bind-required (cdr varlist) (cdr args))))))
!
;;; %TRY-OPTIONAL determines whether the lambda-list keyword &OPTIONAL
;;; has been found.  If so, optional parameters are processed; if not,
;;; the buck is passed to %TRY-REST.

(defun %try-optional (varlist args)
  (cond ((eq (car varlist) '&optional)
	 (%bind-optional (cdr varlist) args))
	(t (%try-rest varlist args))))

;;; %BIND-OPTIONAL determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-optional (varlist args)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn%)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  %lexp% %oldargs%))))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%try-rest varlist args)
			(%process-optional varlist args varspec nil nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-optional varlist args
				       (car varspec)
				       (cadr varspec)
				       (caddr varspec)))
		   (t (%bad-lambda-exp "malformed optional parameter specifier")))))))

;;; %PROCESS-OPTIONAL takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-optional (varlist args var init varp)
  (let ((value (if (null args) (%eval init) (car args))))
    (%varbind var value
      (if varp
	  (%varbind varp (not (null args))
	    (%bind-optional (cdr varlist) (cdr args)))
	  (%bind-optional (cdr varlist) (cdr args))))))
!
;;; %TRY-REST determines whether the lambda-list keyword &REST
;;; has been found.  If so, the rest parameter is processed;
;;; if not, the buck is passed to %TRY-KEY, after a check for
;;; too many arguments.

(defun %try-rest (varlist args)
  (cond ((eq (car varlist) '&rest)
	 (%bind-rest (cdr varlist) args))
	((and (not (eq (car varlist) '&key))
	      (not (null args)))
	 (%lambda-apply-retry lexp
			      (cerror :too-many-arguments
				      "Too many arguments for function ~S: ~S"
				      %lexp% %oldargs%)))
	(t (%try-key varlist args))))

;;; %BIND-REST ensures that there is a parameter specifier for
;;; the &REST parameter, binds it, and then evaluates the body or
;;; calls %TRY-KEY.

(defun %bind-rest (varlist args)
  (cond ((or (endp varlist)
	     (not (symbolp (car varlist))))
	 (%bad-lambda-exp "missing rest parameter specifier"))
	(t (%varbind (car varlist) args
	     (cond ((endp (cdr varlist))
		    (%lambda-evprogn%))
		   ((and (symbolp (cadr varlist))
			 (%lambda-keyword-p (cadr varlist)))
		    (%try-key (cdr varlist) args))
		   (t (%bad-lambda-exp "malformed after rest parameter specifier")))))))
!
;;; %TRY-KEY determines whether the lambda-list keyword &KEY
;;; has been found.  If so, keyword parameters are processed;
;;; if not, the buck is passed to %TRY-AUX.

(defun %try-key (varlist args)
  (cond ((eq (car varlist) '&key)
	 (%bind-key (cdr varlist) args nil))
	(t (%try-aux varlist))))

;;; %BIND-KEY determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-key (varlist args keys)
  (cond ((endp varlist)
	 (%check-for-bad-keywords args keys)
	 (%lambda-evprogn%))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(cond ((not (eq varspec '&allow-other-keywords))
			       (%check-for-bad-keywords args keys)
			       (%try-aux varlist))
			      ((endp (cdr varlist))
			       (%lambda-evprogn%))
			      ((%lambda-keyword-p (cadr varlist))
			       (%try-aux (cdr varlist)))
			      (t (%bad-lambda-exp "invalid after &ALLOW-OTHER-KEYWORDS")))
			(%process-key varlist args keys
				      (intern (symbol-print-name varspec) keyword-package)
				      varspec nil nil)))
		   ((and (consp varspec)
			 (or (symbolp (car varspec))
			     (and (consp (car varspec))
				  (consp (cdar varspec))
				  (symbolp (cadar varspec))
				  (endp (cddar varspec))))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-key varlist args keys
				  (if (consp (car varspec))
				      (caar varspec)
				      (intern (symbol-print-name (car varspec)) keyword-package))
				  (if (consp (car varspec))
				      (cadar varspec)
				      (car varspec))
				  (cadr varspec)
				  (caddr varspec)))
		   (t (%bad-lambda-exp "malformed keyword parameter specifier")))))))

;;; Optional error check for bad keywords.

(defun %check-for-bad-keywords (args keys)
  (do ((a args (cddr a)))
      ((endp args))
    (unless (memq (car a) keys)
      (cerror :unexpected-keyword
	      "Keyword not expected by function ~S: ~S"
	      %lexp% (car a)))))

;;; %PROCESS-KEY takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-key (varlist args keys kwd var init varp)
  (do ((a args (cddr a)))
      ((endp a)
       (%process-key-1 varlist args keys kwd var init varp (%eval init) nil))
    (when (eq (car a) kwd)
      (return (%process-key-1 varlist args keys kwd var init varp (cadr a) t)))))

(defun %process-key-1 (varlist args keys kwd var init varp value suppliedp)
  (%varbind var value
    (if varp
	(%varbind varp suppliedp
	  (%bind-key varlist args (cons kwd keys)))
	(%bind-key varlist args (cons kwd keys)))))
!
;;; %TRY-AUX determines whether the keyword &AUX
;;; has been found.  If so, auxiliary variables are processed;
;;; if not, an error is signalled.

(defun %try-aux (varlist)
  (cond ((eq (car varlist) '&aux)
	 (%bind-aux (cdr varlist)))
	(t (%bad-lambda-exp "unknown or misplaced lambda-list keyword"))))

;;; %BIND-AUX determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-aux (varlist)
  (cond ((endp varlist)
	 (%lambda-evprogn%))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%bad-lambda-exp "unknown or misplaced lambda-list keyword")
			(%process-aux varlist varspec nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (endp (cddr varspec)))
		    (%process-aux varlist (car varspec) (cadr varspec)))
		   (t (%bad-lambda-exp "malformed aux variable specifier")))))))

;;; %PROCESS-AUX takes care of binding the auxiliary variable.

(defun %process-aux (varlist var init)
    (%varbind var (and init (%eval init))
       (%bind-aux varlist)))

(defun %lambda-evprogn ()
  (unless (null %form%) (%eval %form%))
  (%evprogn %body%))
!
;;; Definitions for various special forms and macros.

(defspec quote (obj) obj)

(defspec function (fn)
  (loop (cond ((consp fn)
	       (cond ((eq (car fn) 'lambda)
		      (return (make-interpreted-closure :function fn
							:venv %venv%
							:fenv %fenv%
							:benv %benv%
							:genv %genv%)))
		     (t (setq fn (cerror :invalid-function
					 "~S is not a valid argument for FUNCTION"
					 fn)))))
	      ((symbolp fn)
	       (let ((slot (assq fn fenv)))
		 (cond (slot
			(case (cadr slot)
			  (macro (setq fn (cerror :invalid-function
						  "The name ~S is invalid for FUNCTION: it names a macro"
						  fn)))
			  (function (return (cddr slot)))
			  (t <implementation-error>)))
		       ((fboundp fn)
			(cond ((special-form-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a special form"
						fn)))
			      ((macro-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a macro"
						fn)))
			      (t (setq fn (symbol-function fn)))))
		       (t (setq fn (cerror :invalid-function
					   "The symbol ~S has no function definition"
					   fn))))))
	      (t (setq fn (cerror :invalid-function
				  "~S is not a valid argument for FUNCTION"
				  fn))))))

(defspec if (pred con &optional alt)
  (if (%eval pred) (%eval con) (%eval alt)))

;;; The BLOCK construct provides a PROGN with a named contour around it.
;;; It is interpreted by first putting an entry onto BENV, consisting
;;; of a 1-list of the name.  This list cell serves as a catch tag.
;;; Then the body is executed.
;;; If a RETURN-FROM is interpreted, a throw occurs.  If the BLOCK
;;; construct is exited for any reason (including falling off the end, which
;;; returns the results of evaluating the last form in the body), the cdr of
;;; the entry is clobbered to be INVALID, to indicate that that particular
;;; entry is no longer valid for RETURN-FROM.

(defspec block (name &body body)
  (let ((slot (list name)))
    (unwind-protect (catch slot
		      (let ((%benv% (cons slot %benv%)))
			(%evprogn body)))
		    (rplaca (cdr slot) 'invalid))))

(defspec return (form)
  (let ((slot (assq nil %benv%)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form))))))

(defspec return-from (name form)
  (let ((slot (assq name %benv%)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form))))))
!
(defmacro prog (vars &rest body)
  (do ((b body (cdr b))
       (decls '() (cons (car b) decls)))
      ((or (endp b)
	   (atom (car b))
	   (not (eq (caar b) 'declare)))
       `(let ,vars ,@(nreverse decls) (block nil (tagbody ,@b))))))

;;; The TAGBODY construct provides a body with GO tags in it.
;;; It is interpreted by first putting one entry onto GENV for
;;; every tag in the body; doing this ahead of time saves searching
;;; at GO time.  A unique cons whose car is NIL is constructed for
;;; use as a unique catch tag.  Then the body is executed.
;;; If a GO is interpreted, a throw occurs, sending as the thrown
;;; value the point in the body after the relevant tag.
;;; If the TAGBODY construct is exited for any reason (including
;;; falling off the end, which produces the value NIL), the car of
;;; the unique marker is clobbered to be INVALID, to indicate that
;;; tags associated with that marker are no longer valid.

(defspec tagbody (&rest body)
  (let ((%genv% %genv%))
    (do ((b body (cdr b))
	 (marker (list nil)))
	((endp p)
	 (block exit
	   (unwind-protect
	    (loop (setq body
			(catch marker
			  (do ((b body (cdr b)))
			      ((endp b) (return-from exit nil))
			    (unless (atom (car b))
			      (%eval (car b)))))))
	    (rplaca marker 'invalid))))
      (when (atom (car b))
	(push (list* (car b) marker (cdr b)) %genv%)))))

(defspec go (tag)
  (let ((slot (assq tag %genv%)))
    (cond ((null slot) (ferror ???<unseen-go-tag>))
	  ((eq (caadr slot) 'invalid) (ferror ???<go-tag-no-longer-valid>))
	  (t (throw (cadr slot) (cddr slot))))))
-------

∂10-Nov-82  0037	JONL at PARC-MAXC 	Re: Quick query about CONSTANTP
Date: 10 NOV 1982 0037-PST
From: JONL at PARC-MAXC
Subject: Re: Quick query about CONSTANTP
To:   Guy.Steele at CMU-10A, common-lisp at SU-AI
cc:   JONL

In response to the message sent  10 November 1982 0006-EST (Wednesday) from Guy.Steele@CMU-10A

Interlisp-D has the (currently undocumented, but "upcoming")
function CONSTANTEXPRESSIONP; it works not only for symbols,
but for other forms such as (QUOTE FOO) and (CONSTANT (LIST 1 2))
-- the latter being somewhat like '#.(LIST 1 2) except that the
evaluation is performed at eval/compile time rather than readtime.
Ultimately CONSTANTEXPRESSIONP should even work of forms like
(COND ((EQ PI PI) 3) (T 4)), but its current status is more limited.

Just exactly how CONSTANTP, or CONSTANTEXPRESSIONP if you care to
follow the Interlisp pattern, is implemented for symbols is
probably not all that important.  But your suggestion of a bit
in the symbol header brings back memories of LISP1.5 which
had certain property names treated specially by the equivalent
of PUTPROP -- namely a word of bits that could be turned on
or off.  If efficiency is important in matters like these
(i.e., system properties whose values are always true or false),
them maybe it's not such a bad idea to have these  property
bits again.  But that's *if* ...

∂10-Nov-82  0526	Scott E. Fahlman <Fahlman at Cmu-20c> 	Quick query about CONSTANTP    
Date: Wednesday, 10 November 1982  08:27-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Quick query about CONSTANTP


I've got no problem with Constantp, or even with a requirement that
resetting a constant in the evaluator signals a correctable error.  I
don't want to do this check in compiled code right now.

-- Scott

∂10-Nov-82  0530	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
Date: Wednesday, 10 November 1982  08:30-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Guy.Steele at CMU-10A
Cc:   common-lisp at SU-AI
Subject: Named lambdas


NAMED-LAMBDA looks like a total crock to me, but we use it anyway.  It
is by far the simplest way for us to keep around the name (or I guess
the function spec) of a lambda for use by the debugger.  I guess this
could be done with a hash-table or something, but that is gruesome.
Our plan was to just use this internally in evaluated DEFUN, but maybe
it would be better to inform the users of this.

-- Scott

∂10-Nov-82  0751	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Named lambdas   
Date: Wednesday, 10 November 1982, 10:46-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Named lambdas
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-reply-to: The message of 9 Nov 82 22:33-EST from Guy.Steele at CMU-10A

Yes, we should have NAMED-LAMBDA.  It is invaluable for debugging if you
ever use interpreted code.

CONSTANTP is OK with me; I have no strong feelings about it.

∂10-Nov-82  0751	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Re: Mini-ballot 
Date: Wednesday, 10 November 1982, 10:44-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Re: Mini-ballot
To: common-lisp at SU-AI
In-reply-to: The message of 8 Nov 82 19:58-EST from Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>,
             The message of 8 Nov 82 20:10-EST from Eric Benson <BENSON at UTAH-20>,
             The message of 9 Nov 82 01:52-EST from Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>,
             The message of 9 Nov 82 04:33-EST from Guy.Steele at CMU-10A,
             The message of 9 Nov 82 07:44-EST from Scott E. Fahlman <Fahlman at Cmu-20c>

    Date:  8 Nov 1982 1810-MST
    From: Eric Benson <BENSON at UTAH-20>
    (1) It should not be necessary to extend DEFUN in this manner.
    (SETF (GET 'FOO 'BAR) #'(LAMBDA ...))
    should do exactly what you want.  Is there a problem with this?
Several.  Among others, a "definition" special form is parsable; on the Lispm
it records the source file name and checks for invalid redefinitions, etc.
I won't bother to go one since this seems to have been decided in the
right direction.

    Date:  8 Nov 1982 1958-EST
    From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
							 Do you gurantee
    that we can always do (APPLY (GET 'FOO 'BAR) args)?
We do guarantee that if you get a function object by calling the appropriate
function (the Lispm calls it FDEFINITION) on the function spec, then you
can apply what you got, but that doesn't mean we have to make any statements
about what you got.

    Date:  9 Nov 1982 0152-EST
    From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
				  However I would like to have someone define
    what the construct for MACRO's, FEXPR's (if Common Lisp has such
    things), and any other odd things that DEFUN can generate.  If it is not
    possible to do that, then I think we would be better off using (PUTPROP
    'FOO 'BAR '#(LAMBDA ...  
Pardon me, but this doesn't make any sense.  The function spec FOO refers
to the function "cell" of FOO, whether it holds a macro or a function or
whatever.  (defmacro (:property foo bar) xxx) would mean to put onto
foo's bar property the same object that (defmacro baz xxx) would have put
into foo's function "cell".  There aren't any alternative constructs for
macros.

			     Furthermore, I would like to request that the
    this definition include a specification of the actual data structure to
    be used for interpreted functions.  
Gee, I thought that defining the format of functions was exactly what you
didn't want to do.  However, FDEFINITION of a defined function-spec is
guaranteed to return a function, suitable for APPLY and FUNCALL; it
is NOT allowed to return (expr lambda ...) or anything like that.
So I think function specs are actually the way to solve the problems that
you are bringing up.

    Date:  9 November 1982 0433-EST (Tuesday)
    From: Guy.Steele at CMU-10A

    I might believe that (APPLY '(:PROPERTY FOO BAR) args) shouldn't work,

In the Lisp Machine, symbols are a special case:  it is defined that all
symbols are functions, and when applied, they apply their definition.
However, it is not defined that all function specs in general are
functions and do the analogous thing just the way symbols do.  Actually,
we could make this change if we wanted, simply by saying that it's
illegal to have a function spec that looks like (LAMBDA ...).  I'm not
convinced that this would be a good idea, though.

    However, if you believe in the thing-name distinction, then it is
    even more important that ((:PROPERTY FOO BAR) 3 5 :START 7) work
This is exactly what I argued, about a year or two ago.  It's the general
"normal evaluation"/"functional evaluation" distinction.  If #'(:property a b)
works then, by analogy, ((:property a b) ...) ought to work.  However:

    Date: Tuesday, 9 November 1982  07:44-EST
    From: Scott E. Fahlman <Fahlman at Cmu-20c>

    I am really getting scared.  Allowing ((:property foo bar) ...) seems to
    me to open up all sorts of evil and hairy possibilities.
This is what everybody else told me, including Moon.  My feeling on the
matter is that we did, frankly, leave a semantic asymmetry in the by
leaving it in its current state.  Zvona's argument that the users expect
((:property a b) ...) to work is an important one: this is an instance
of a fundamental principle of user-interface, which makes sense applied
to language design too.  I still feel that ((:property a b) ...) really
ought to work, but I have already accepted Fahlman's argument and am
slightly scared myself.  Note that I don't know what Moon thinks about
this; I haven't discused it with him in some time.

As for the asterisks issue, I abstain (I don't think I have anything
useful to contribute and you guys seem to have the issue under control).

∂11-Nov-82  0725	Masinter at PARC-MAXC 	Named lambdas    
Date: 11-Nov-82  7:26:02 PST (Thursday)
From: Masinter at PARC-MAXC
Subject: Named lambdas
To: common-lisp at SU-AI

I can nowhere find a description of NAMED-LAMBDA and its semantics.
I've made a guess, but it doesn't map very well into extant common-lisp
structures; e.g., who can see the name? I assume from the discussion
about debuggers that the name is dynamic in scope rather than lexical.

∂11-Nov-82  0750	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
Date: Thursday, 11 November 1982  10:47-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Masinter at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Named lambdas


Named-Lambda was invented by the Lisp Machine folk (I think).  The
syntax is

(NAMED-LAMBDA name arglist . body)

This works in all respects like a lambda, with the name being ignored.
The name is there solely for debugging.  The reason this exists is that
interpreted DEFUN can now put the named-lambda form in the function slot
of a symbol, with the name indicating the name of the function as seen
by DEFUN.  (I guess now this is a function-spec.)  No attempt is made to
keep this up to date if the form is passed around to other places.  At
various times in the interpreter, only the lambda or named-lambda form
is on the stack, and if it is a named-lambda, the debugger can say
something intelligent about what the function is.  In some
implementations, at least, it is very hard to recover the name of the
function in any other way -- it does not appear on the stack in any
meaningful form.  Assorted other code-browsing functions may also find
the name useful.

Since the name is just commentary, and doesn't really do anything, I
don't think that the scoping issues apply.  I'm not really sure whether
lambdas created inside a LABELS or some such would be named -- this
would be used so rarely that I don't really care.  The point is to do
something useful for the normal case of a DEFUN.

-- Scott

∂11-Nov-82  0824	Masinter at PARC-MAXC 	Re: Named lambdas
Date: 11-Nov-82  8:21:52 PST (Thursday)
From: Masinter at PARC-MAXC
Subject: Re: Named lambdas
In-reply-to: Fahlman's message of Thursday, 11 November 1982  10:47-EST
To: Scott E. Fahlman <Fahlman at Cmu-20c>
cc: Masinter, common-lisp at SU-AI

My reading of what you say is that, as far as the semantics of what is
accessible from common-lisp functions, the name in NAMED-LAMBDA is just 
commentary? You say how NAMED-LAMBDA is used, but not what it means.

I don't quite understand about interpreted DEFUNs. Do you mean

(DEFUN FOO (NAMED-LAMBDA FUM (A B C) --))

that the debugger will show FUM on the stack? There's nothing so far in common
lisp which had led me to believe that if you said

(DEFUN FOO (A B C) --) 

that the debugger COULDN'T tell that you were inside FOO; I don't believe
such enforced brain-damage should be in the spec for Common-Lisp.

Also: does NAMED-LAMBDA have a different meaning for compiled & interpreted code?
I.e., they get thrown away when you interpret?



∂11-Nov-82  0857	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
Date: Thursday, 11 November 1982  11:54-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   Masinter at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Named lambdas


Yes, the name in named-lambda is just machine-readable commentary -- the
evaluator just ignores it.

(defun foo (a b c) ...)

puts

(NAMED-LAMBDA FOO (A B C) ...)

into the symbol-function slot of the symbol FOO, instead of the more
traditional

(LAMBDA (A B C) ...)

When the DEFUN gets compiled, the name is hidden in the compiled
function object, so similar debugging information is available.  In the
Spice Lisp implementation, at least, the LAMBDA form is on the stack,
but not the calling form, so it would be awkward (not impossible) to
recover the function name for debugging; the NAMED-LAMBDA hack solves
the problem.  This is something of a kludge, and I have no strong
opinion about whether it should be in the white pages or whether we
should just quietly do our dirty hacking behind the scenes.  The only
problem is that users might see named-lambdas on the stack and wonder
what is up, so they at least have to be documented in the red pages of
implementations that use this trick.

-- Scott

∂11-Nov-82  0943	Eric Benson <BENSON at UTAH-20> 	Re: Quick query about CONSTANTP 
Date: 11 Nov 1982 1042-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: Quick query about CONSTANTP
To: Guy.Steele at CMU-10A, common-lisp at SU-AI
In-Reply-To: Your message of 9-Nov-82 2206-MST

Uh-oh, CONSTANTP is defined in Standard Lisp already and means
(AND (NOT (CONSP X)) (NOT (SYMBOLP X))).  If you put this in, please
call it something (slightly) different, e.g. CONSTANT-P.  By the way,
I do think this is a useful idea.  I think it's important not to leave
too much undefined in the standard.  For example, it would be very nice
if a function (not special form) were defined for defining macros, and
there should be some way to find out how many multiple values are
returned by a function without having to make a list of them.
-------

∂11-Nov-82  1253	Guy.Steele at CMU-CS-A 	Benson's remarks on CONSTANTP  
Date: 11 November 1982 1549-EST (Thursday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: Benson's remarks on CONSTANTP
In-Reply-To: Eric Benson's message of 11 Nov 82 12:42-EST

I must say that when I hear the functio name CONSTANTP my first
thought is "Oh, that tells you whether or not something self-evaluates";
clearly Standard LISP has given that name its natural definition.
What I have proposes is probably better called CONSTANT-SYMBOL-P.
--Guy

∂11-Nov-82  1348	Earl A. Killian            <Killian at MIT-MULTICS> 	primitives  
Date:     11 November 1982 1302-pst
From:     Earl A. Killian            <Killian at MIT-MULTICS>
Subject:  primitives
To:       Common-Lisp at SU-AI

I am somewhat concerned about the lack of primitives in Common-Lisp.
Usually the Common Lisp language design has been oriented toward
high-level features.  This is good, but it is not sufficient.  For
example, DEFCONSTANT was defined at a high-level; people thought about
what they wanted to write in their source programs and specified that as
the behavoir of DEFCONSTANT.  What bothers me is that no facilities were
provided so that the user could write DEFCONSTANT (or more likely, a
variant thereof) himself.  In this example, there is no function that
examines or sets a symbols constantness.  A recent proposal has asked
for CONSTANTP; if (SETF (CONSTANTP 'X) ...) also works, then I would be
satisfied in this case.

I think that are a number of other cases like this one.  We should take
a close look at the next language manual sent to us and try to identify
those high-level parts of the language that should be suplemented by
low-level primitives.  A good way to locate these is to look for
facilities that work only for unevaluated arguments (such as
DEFCONSTANT) or exist at only one of several levels of abstraction (such
as the compiler).

Some more examples:

- A lower-level interface to the compiler should exist.  How about
  something that takes a lambda expression and some other things (e.g. a
  name for debugging) and returns a compiled code object.

- I think DEFUN/DEFMACRO/DEFTYPE should be definable by the user in
  terms of functions with evaluated arguments.  They should be part of a
  Common Lisp library, and not implementation dependent.
  The recent suggestion to expand
  (DEFUN F ARGS BODY)
  into
  (SETF (SYMBOL-FUNCTION-VALUE 'F) #'(LAMBDA ARGS BODY))
  is simplistic, but this is not a fatal flaw.  There should be a
  function (ie. something that evaluates its arguments) like the LISPM's
  FDEFINE or FSET-CAREFULLY or whatever that sets a function cell with
  all the hair of remembering source files and giving warnings and
  whatever other objections were given against the simple SETF.

- Dynamic binding.  PROGV comes close to being a primitive, but is
  cumbersome and only works for the value cell of symbols.

∂11-Nov-82  1349	Earl A. Killian            <Killian at MIT-MULTICS> 	primitives  
Date:     11 November 1982 1302-pst
From:     Earl A. Killian            <Killian at MIT-MULTICS>
Subject:  primitives
To:       Common-Lisp at SU-AI

I am somewhat concerned about the lack of primitives in Common-Lisp.
Usually the Common Lisp language design has been oriented toward
high-level features.  This is good, but it is not sufficient.  For
example, DEFCONSTANT was defined at a high-level; people thought about
what they wanted to write in their source programs and specified that as
the behavoir of DEFCONSTANT.  What bothers me is that no facilities were
provided so that the user could write DEFCONSTANT (or more likely, a
variant thereof) himself.  In this example, there is no function that
examines or sets a symbols constantness.  A recent proposal has asked
for CONSTANTP; if (SETF (CONSTANTP 'X) ...) also works, then I would be
satisfied in this case.

I think that are a number of other cases like this one.  We should take
a close look at the next language manual sent to us and try to identify
those high-level parts of the language that should be suplemented by
low-level primitives.  A good way to locate these is to look for
facilities that work only for unevaluated arguments (such as
DEFCONSTANT) or exist at only one of several levels of abstraction (such
as the compiler).

Some more examples:

- A lower-level interface to the compiler should exist.  How about
  something that takes a lambda expression and some other things (e.g. a
  name for debugging) and returns a compiled code object.

- I think DEFUN/DEFMACRO/DEFTYPE should be definable by the user in
  terms of functions with evaluated arguments.  They should be part of a
  Common Lisp library, and not implementation dependent.
  The recent suggestion to expand
  (DEFUN F ARGS BODY)
  into
  (SETF (SYMBOL-FUNCTION-VALUE 'F) #'(LAMBDA ARGS BODY))
  is simplistic, but this is not a fatal flaw.  There should be a
  function (ie. something that evaluates its arguments) like the LISPM's
  FDEFINE or FSET-CAREFULLY or whatever that sets a function cell with
  all the hair of remembering source files and giving warnings and
  whatever other objections were given against the simple SETF.

- Dynamic binding.  PROGV comes close to being a primitive, but is
  cumbersome and only works for the value cell of symbols.

∂12-Nov-82  0003	MOON at SCRC-TENEX 	Named lambdas  
Date: Friday, 12 November 1982  01:47-EST
From: MOON at SCRC-TENEX
To:   Scott E. Fahlman <Fahlman at Cmu-20c>
Cc:   common-lisp at SU-AI, Masinter at PARC-MAXC
Subject: Named lambdas
In-reply-to: The message of 11 Nov 1982  10:47-EST from Scott E. Fahlman <Fahlman at Cmu-20c>

Lambdas created by a LABELS would be named, with :INTERNAL function-specs.

Also note that in the Lisp machine the format got expanded to
(NAMED-LAMBDA (name . other-data) (args...) body...).  If Common Lisp
standardizes on NAMED-LAMBDA it should perhaps only have this format.
Other-data is used for dozens of things.

∂12-Nov-82  0100	MOON at SCRC-TENEX 	primitives, and dynamic binding    
Date: Friday, 12 November 1982  02:31-EST
From: MOON at SCRC-TENEX
To:   Earl A. Killian <Killian at MIT-MULTICS>
Cc:   Common-Lisp at SU-AI
Subject: primitives, and dynamic binding
In-reply-to: The message of 11 Nov 1982 1302-pst from Earl A. Killian            <Killian at MIT-MULTICS>

    Date:     11 November 1982 1302-pst
    From:     Earl A. Killian            <Killian at MIT-MULTICS>

    I am somewhat concerned about the lack of primitives in Common-Lisp.

I agree with you.  There is a problem, though, which is that if you specify
too many primitives you put a lot of constraints on the implementation.  This
doesn't apply to all of the specific points you brought up in your message,
though.

I think at this point the best thing would be to recognize that we are
specifying the first version of Common Lisp, and contrary to what it says
about stability in the front of the manual, there is going to be a fairly
large update in 6 months to a year.  It might be easier to put in the missing
primitives then.  Of course the danger of this is that each implementation
will have its own slightly incompatible primitives already by then.  But this
isn't really different from the situation we started with, with multiple
incompatible dialects.  If people are willing to be flexible we can adjust
our primitives to meet a common standard, or argue when techniques used in
a particular implementation rule out adherence to the proposed standard.

I do think it is important for the long-term success of the language that
as few of the underlying primitives as possible be concealed from the user.

    - Dynamic binding.  PROGV comes close to being a primitive, but is
      cumbersome and only works for the value cell of symbols.

This is a good case in point.  I would agree with you that there should be a
true binding primitive (although note that it would require adding locatives
to the language), however this would put fairly strong restrictions on
possible implementation techniques.  In fact the Common Lisp implementation
proposed for -your very own- machine can -only- bind the value cells of
symbols, because it uses deep binding, because it is a multi-processor with
a von Neumann memory.

∂12-Nov-82  0608	Kent M. Pitman <KMP at MIT-MC> 	primitives   
Date: 12 November 1982 09:08-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  primitives
To: Moon at SCRC-TENEX
cc: Common-Lisp at SU-AI

    Date: Friday, 12 November 1982  02:31-EST
    From: MOON at SCRC-TENEX

    ... there is going to be a fairly large update in 6 months to a year.  It
    might be easier to put in the missing primitives then.  Of course the
    danger of this is that each implementation will have its own slightly
    incompatible primitives already by then...

Agreed. But users take what comes if they rely on such things as are not
in the language spec even if they are in an implementation. I think we 
should certainly be willing to discuss proposals for standardizing on
primitives, but there is no reason we have to rush to any decisions. We 
should keep in mind that it's always easier to add new primitives than to
remove ones we decide should never have been... 

∂12-Nov-82  0932	Eric Benson <BENSON at UTAH-20> 	Re: primitives   
Date: 12 Nov 1982 1030-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: primitives
To: Killian at MIT-MULTICS, Common-Lisp at SU-AI
In-Reply-To: Your message of 11-Nov-82 1402-MST

Amen.  That's what I was getting at in my last message.  The number of
primitives that can't be written in the language itself can and should
be very small.  Now that controversies over user-level features seem
to be dying down, let's fill in the gaps.
-------

∂12-Nov-82  1000	Earl A. Killian            <Killian at MIT-MULTICS> 	NAMED-LAMBDA
Date:     12 November 1982 0931-pst
From:     Earl A. Killian            <Killian at MIT-MULTICS>
Subject:  NAMED-LAMBDA
To:       common-lisp at SU-AI

This is ok with me, but I would like to clarify some things about it.

Fahlman has said twice that you put (NAMED-LAMBDA name args . body) in
the function cell of symbols.  That may be true on the LispM or PERQ,
but on a conventional architecture I'd never put anything but a compiled
function pointer in the function cell in order to keep function calling
fast. Instead, I'd have interpreted DEFUN create a tiny compiled transfer
function to an EVAL entrypoint with the lambda expression as an
argument.  And actually it wouldn't be DEFUN that did this: the compiled
transfer function would be the result of evaluating a LAMBDA or
NAMED-LAMBDA.  This is actually a good argument against allowing
(APPLY '(LAMBDA ...) ...) since that implies that
(SETF (SYMBOL-FUNCTION-VALUE 'F) '(LAMBDA ...)) will work.  I'd be very
upset if Common-Lisp tried to force that on an implementation.  For
efficiency on a conventional architecure, I'd also make all functions be
closures, i.e. have a lexical environment, even if it is ().  That's
another reason not to put lambda forms into function cells.

Thus, on conventional machines, users would almost never see
NAMED-LAMBDAs.  The name for debugging would be presumably be retreived
from this compiled transfer function.  The only use of NAMED-LAMBDA is
as a way for DEFUN to communicate the name to whatever creates the
transfer code.

∂12-Nov-82  1025	Earl A. Killian            <Killian at MIT-MULTICS> 	#,
Date:     12 November 1982 1021-pst
From:     Earl A. Killian            <Killian at MIT-MULTICS>
Subject:  #,
To:       common-lisp at SU-AI

Shouldn't #, be a reader abbreviations for some form just like ' is?
Otherwise, how do you have a macro that uses the load-time-eval facility
for constructed code?

∂12-Nov-82  1231	MOON at SCRC-TENEX 	NAMED-LAMBDA and function cells    
Date: Friday, 12 November 1982  15:23-EST
From: MOON at SCRC-TENEX
To:   Earl A. Killian <Killian at MIT-MULTICS>
Cc:   common-lisp at SU-AI
Subject: NAMED-LAMBDA and function cells
In-reply-to: The message of 12 Nov 1982 0931-pst from Earl A. Killian            <Killian at MIT-MULTICS>

    Date:     12 November 1982 0931-pst
    From:     Earl A. Killian            <Killian at MIT-MULTICS>

    This is actually a good argument against allowing
    (APPLY '(LAMBDA ...) ...)

Now there's a significant break with the past!

The rest of your message is a result of confusing two different meanings for
the term "function cell."  One is an internal object of the implementation,
the part of a symbol through which calls to a function named by that symbol
indirect.  The other is that conceptual piece of storage manipulated by the
FDEFINE and FDEFINITION primitives, or (at a lower level) SYMBOL-FUNCTION-VALUE
and its SETF.  These happen to be the same in the Lisp machine, and I guess
in the PERQ, but there is no reason for them to be the same.  The former is
implementation-dependent and its goal is to make function calling efficient.
The latter is Common-Lisp-defined and its goal is to allow portable programs
to manipulate function definitions.  What the machine sees must be efficient;
what the user sees must be portable.  (Read "ought" for "must" if you like).

∂12-Nov-82  1327	Eric Benson <BENSON at UTAH-20> 	Re: NAMED-LAMBDA and function cells  
Date: 12 Nov 1982 1426-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: NAMED-LAMBDA and function cells
To: MOON at SCRC-TENEX at MIT-MC, Killian at MIT-MULTICS
cc: common-lisp at SU-AI
In-Reply-To: Your message of 12-Nov-82 1341-MST

If you like, this is another wart which has been retained in Common Lisp,
like (SYMBOLP ()).  I think most of us would agree that the Scheme
approach is much more sensible, since it eliminates the "name vs. use"
problem, as in (:PROPERTY FOO BAR), etc.  Like the () vs. NIL, this has
2 effects: confusing semantics and difficulty or inefficiency of
implementation.  Too bad, but that's the price of compatibility with the
past.

P.S. Brian Smith's thesis should be required reading (at least browsing)
for all of us.  I know we can't change Lisp too radically, but we should
be conscious of the kludges we are perpetuating.
-------

∂12-Nov-82  2157	STEELE at CMU-20C 	Revised evaluators   
Date: 13 Nov 1982 0054-EST
From: STEELE at CMU-20C
Subject: Revised evaluators
To: common-lisp at SU-AI

The enclosed two revised evaluators include changes for the following
bugs noted by Bawden:
(1) EVALHOOK was incorrectly hooking on the given form; it should only
hook on subforms.  To this end %EVAL was split into two parts %EVAL
and %EVAL1.
(2) Two ocurrences of LEXP in%LAMBDA-APPLY-1 should have been NEWFN.
(3) The PROG macro was failing to call MACROEXPAND when looking for
declarations.

Also, %VARBIND and %LAMBDA-APPLY-1 were changed, and a new function
%ADD-SPECIALS introduced, to fix a bug in the handling of SPECIAL
declarations.  One wants
	(DEFUN BLAG (X)
	  (DECLARE (SPECIAL *BARF*))
	  ...)
to cause *BARF* to be special in the body of BLAG even though BLAG does
not bind *BARF*.  The new evaluators should fix this problem.
--Guy
-------------------------------------------------------------
;;; This evaluator splits the lexical environment into four
;;; logically distinct entities:
;;;	VENV = lexical variable environment
;;;	FENV = lexical function and macro environment
;;;	BENV = block name environment
;;;	GENV = go tag environment
;;; Each environment is an a-list.  It is never the case that
;;; one can grow and another shrink simultaneously; the four
;;; parts could be united into a single a-list.  The four-part
;;; division saves consing and search time.
;;;
;;; Each entry in VENV has one of two forms: (VAR VALUE) or (VAR).
;;; The first indicates a lexical binding of VAR to VALUE, and the
;;; second indicates a special binding of VAR (implying that the
;;; special value should be used).
;;;
;;; Each entry in FENV looks like (NAME TYPE . FN), where NAME is the
;;; functional name, TYPE is either FUNCTION or MACRO, and FN is the
;;; function or macro-expansion function, respectively.  Entries of
;;; type FUNCTION are made by FLET and LABELS; those of type MACRO
;;; are made by MACROLET.
;;;
;;; Each entry in BENV looks like (NAME), where NAME is the name
;;; of the block.  The cons cell that is the entry is used as a
;;; catch tag for implementing RETURN-FROM.  If the entry has been
;;; clobbered to look like (NAME . INVALID), then the block has
;;; been exited, and a return to that block is an error.
;;;
;;; Each entry in GENV looks like (TAG MARKER . BODY), where TAG is
;;; a go tag, MARKER is a unique cons used as a catch tag, and BODY
;;; is the statement sequence that follows the go tag.  If the car of
;;; MARKER, normally NIL, has been clobbered to be INVALID, then
;;; the tag body has been exited, and a GO to that tag is an error.

;;; An interpreted-lexical-closure contains a function (normally a
;;; lambda-expression) and the lexical environment.

(defstruct interpreted-lexical-closure function venv fenv benv genv)


;;; The EVALHOOK feature allows a user-supplied function to be called
;;; whenever a form is to be evaluated.  The presence of the lexical
;;; environment requires an extension of the feature as it is defined
;;; in MacLISP.  Here, the user hook function must accept not only
;;; the form to be evaluated, but also the components of the lexical
;;; environment; these must then be passed verbatim to EVALHOOK or
;;; *EVAL in order to perform the evaluation of the form correctly.
;;; The precise number of components should perhaps be allowed to be
;;; implementation-dependent, so it is probably best to require the
;;; user hook function to accept arguments as (FORM &REST ENV) and
;;; then to perform evaluation by (APPLY #'EVALHOOK FORM HOOKFN ENV),
;;; for example.

(defvar *evalhook* nil)

(defun evalhook (exp hookfn venv fenv benv genv)
  (let ((*evalhook* hookfn)) (%eval1 exp venv fenv benv genv)))

(defun eval (exp)
  (*eval exp nil nil nil nil))

;;; *EVAL looks useless here, but does more complex things
;;; in alternative implementations of this evaluator.

(defun *eval (exp venv fenv benv genv)
  (%eval exp venv fenv benv genv))
!
;;; Function names beginning with "%" are intended to be internal
;;; and not defined in the Common LISP white pages.

;;; %EVAL is the main evaluation function.  It is split into two
;;; parts, with the main part called %EVAL1, for the benefit of EVALHOOK.

(defun %eval (exp venv fenv benv genv)
  (if *evalhook*
      (let ((hookfn *evalhook*) (*evalhook* nil))
	(funcall hookfn exp venv fenv benv genv))
      (t (%eval1 exp venv fenv benv genv))))

(defun %eval1 (exp venv fenv benv genv)
  (typecase exp
    ;; A symbol is first looked up in the lexical variable environment.
    (symbol (let ((slot (assq exp venv)))
	      (cond ((and slot (not (null (cdr slot))))
		     (cadr slot))
		    ((boundp exp) (symbol-value exp))
		    (t (cerror :unbound-variable
			       "The symbol ~S has no value"
			       exp)))))
    ;; Numbers, strings, bit-vectors, and characters self-evaluate.
    ((or number string bit-vector character) exp)
    ;; Conses require elaborate treatment based on the car.
    (cons (typecase (car exp)
	    ;; A symbol is first looked up in the lexical function environment.
	    ;; This lookup is cheap if the environment is empty, a common case.
	    (symbol
	     (let ((fn (car exp)))
	       (loop (let ((slot (assq fn fenv)))
		       (unless (null slot)
			 (return (case (cadr slot)
				   (macro (%eval (%macroexpand
						  (cddr slot)
						  (if (eq fn (car exp))
						      exp
						      (cons fn (cdr exp))))))
				   (function (%apply (cddr slot)
						     (%evlis (cdr exp) venv fenv benv genv)
						     venv fenv benv genv))
				   (t <implementation-error>)))))
		     ;; If not in lexical function environment,
		     ;;  try the definition cell of the symbol.
		     (when (fboundp fn)
		       (return (cond ((special-form-p fn)
				      (%invoke-special-form
				       fn (cdr exp) venv fenv benv genv))
				     ((macro-p fn)
				      (%eval (%macroexpand
					      (get-macro-function (symbol-function fn))
					      (if (eq fn (car exp))
						  exp
						  (cons fn (cdr exp))))
					     venv fenv benv genv))
				     (t (%apply (symbol-function fn)
						(%evlis (cdr exp) venv fenv benv genv)
						venv fenv benv genv)))))
		     (setq fn
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
		     (unless (symbolp fn)
		       (return (%apply fn
				       (%evlis (cdr exp) venv fenv benv genv)
				       venv fenv benv genv))))))
	    ;; A cons in function position must be a lambda-expression.
	    ;; Note that the construction of a lexical closure is avoided here.
	    (cons (%apply (car exp)
			  (%evlis (cdr exp) venv fenv benv genv)
			  venv fenv benv genv))
	    (t (%eval (cerror :invalid-form
			      "Cannot evaluate the form ~S: function position has invalid type ~S"
			      exp (type-of (car exp)))
		      venv fenv benv genv))))
    (t (%eval (cerror :invalid-form
		      "Cannot evaluate the form ~S: invalid type ~S"
		      exp (type-of exp))
	      venv fenv benv genv))))
!
;;; Given a list of forms, evaluate each and return a list of results.

(defun %evlis (forms venv fenv benv genv)
  (mapcar #'(lambda (form) (%eval form venv fenv benv genv)) forms))

;;; Given a list of forms, evaluate each, discarding the results of
;;; all but the last, and returning all results from the last.

(defun %evprogn (body venv fenv benv genv)
  (if (endp body) nil
      (do ((b body (cdr b)))
	  ((endp (cdr b))
	   (%eval (car b) venv fenv benv genv))
	(%eval (car b) venv fenv benv genv))))

;;; APPLY takes a function, a number of single arguments, and finally
;;; a list of all remaining arguments.  The following song and dance
;;; attempts to construct efficiently a list of all the arguments.

(defun apply (fn firstarg &rest args*)
  (%apply fn
	  (cond ((null args*) firstarg)
		((null (cdr args*)) (cons firstarg (car args*)))
		(t (do ((x args* (cdr x))
			(z (cddr args*) (cdr z)))
		       ((null z)
			(rplacd x (cadr x))
			(cons firstarg (car args*))))))
	  nil nil nil nil))
!
;;; %APPLY does the real work of applying a function to a list of arguments.
;;; The environment is passed in because it leads to more natural error
;;; recovery.

(defun %apply (fn args venv fenv benv genv)
  (typecase fn
    ;; For a compiled function, an implementation-dependent "spread"
    ;;  operation and invocation is required.
    (compiled-function (%invoke-compiled-function fn args))
    ;; The same goes for a compiled closure over lexical variables.
    (compiled-lexical-closure (%invoke-compiled-lexical-closure fn args))
    ;; The treatment of interpreted lexical closures is elucidated fully here.
    (interpreted-lexical-closure
     (%lambda-apply (interpreted-lexical-closure-function fn)
		    args
		    (interpreted-lexical-closure-venv fn)
		    (interpreted-lexical-closure-fenv fn)
		    (interpreted-lexical-closure-benv fn)
		    (interpreted-lexical-closure-genv fn)))
    ;; For a symbol, the function definition is used, if it is a function.
    (symbol (%apply (cond ((not (fboundp fn))
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
			  ((special-form-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a special form"
				   fn))
			  ((macro-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a macro"
				   fn))
			  (t (symbol-function fn)))
		    args venv fenv benv genv))
    (cons (if (eq (car fn) 'lambda)
	      (%lambda-apply fn args venv fenv benv genv)
	      (%apply (cerror :invalid-function
			      "~S is not a valid function"
			      fn)
		      args venv fenv benv genv)))
    (t (%apply (cerror :invalid function
		       "~S has an invalid type ~S for a function"
		       fn (type-of fn))
	       args venv fenv benv genv))))
!
;;; %LAMBDA-APPLY is the hairy part, that takes care of applying
;;; a lambda-expression in a given lexical environment to given
;;; arguments.  The complexity arises primarily from the processing
;;; of the parameter list.
;;;
;;; If at any point the lambda-expression is found to be malformed
;;; (typically because of an invalid parameter list), or if the list
;;; of arguments is not suitable for the lambda-expression, a correctable
;;; error is signalled; correction causes a throw to be performed to
;;; the tag %LAMBDA-APPLY-RETRY, passing back a (possibly new)
;;; lambda-expression and a (possibly new) list of arguments.
;;; The application is then retried.  If the new lambda-expression
;;; is not really a lambda-expression, then %APPLY is used instead of
;;; %LAMBDA-APPLY.
;;;
;;; In this evaluator, PROGV is used to instantiate variable bindings
;;; (though its use is embedded with a macro called %varbind).
;;; The throw that precedes a retry will cause special bindings to
;;; be popped before the retry.

(defun %lambda-apply (lexp args venv fenv benv genv)
  (multiple-value-bind (newfn newargs)
		       (catch '%lambda-apply-retry
			 (return-from %lambda-apply
			   (%lambda-apply-1 lexp args venv fenv benv genv)))
    (if (and (consp newfn) (eq (car newfn) 'lambda))
	(%lambda-apply newfn newargs venv fenv benv genv)
	(%apply newfn newargs venv fenv benv genv))))

;;; Calling this function will unwind all special variables
;;; and cause FN to be applied to ARGS in the original lexical
;;; and dynamic environment in force when %LAMBDA-APPLY was called.

(defun %lambda-apply-retry (fn args)
  (throw '%lambda-apply-retry (values fn args)))

;;; This function is convenient when the lambda expression is found
;;; to be malformed.  REASON should be a string explaining the problem.

(defun %bad-lambda-exp (lexp oldargs reason)
  (%lambda-apply-retry
   (cerror :invalid-function
	   "Improperly formed lambda-expression ~S: ~A"
	   lexp reason)
   oldargs))

;;; (%varbind VAR VALUE . BODY) evaluates VAR to produce a symbol name
;;; and VALUE to produce a value.  If VAR is determined to have been
;;; declared special (as indicated by the current binding of the variable
;;; SPECIALS, which should be a list of symbols, or by a SPECIAL property),
;;; then a special binding is established using PROGV.  Otherwise an
;;; entry is pushed onto the a-list presumed to be in the variable VENV.

;;; The CONSTANTP test ideally is true for any constant symbol;
;;; it should at least check for T, NIL, and keywords.

(defmacro %varbind (var value &body body)
  (let ((xvar (gensym)) (xvalue (gensym)))
    `(let ((,xvar ,var) (,xvalue ,value))
       (loop (when (not (constantp ,xvar)) (return))
	     (setq ,xvar (cerror :invalid-variable
				 "~S is a constant and may not be bound"
				 ,xvar)))
       (let ((specp (or (memq ,xvar specials) (get ,xvar 'special))))
	 (progv (and specp (list ,xvar)) (and specp (list ,xvalue))
		(unless specp (push (list ,xvar ,xvalue) venv))
		,@body)))))

;;; %LAMBDA-KEYWORD-P is true iff X (which must be a symbol)
;;; has a name beginning with an ampersand.

(defun %lambda-keyword-p (x)
  (char= #\& (char 0 (symbol-pname x))))
!
;;; %LAMBDA-APPLY-1 is responsible for verifying that LEXP is
;;; a lambda-expression, for extracting a list of all variables
;;; declared SPECIAL in DECLARE forms, and for finding the
;;; body that follows any DECLARE forms.

(defun %lambda-apply-1 (lexp args venv fenv benv genv)
  (cond ((or (not (consp lexp))
	     (not (eq (car lexp) 'lambda))
	     (atom (cdr lexp))
	     (not (listp (cadr lexp))))
	 (%bad-lambda-exp lexp args "improper lambda-expression"))
	(t (do ((body (cddr lexp) (cdr body))
		(specials '()))
	       ((or (endp body) (not (consp (car body))))
		(%bind-required lexp args (cadr lexp)
				(%add-specials venv specials)
				fenv benv genv args specials nil body))
	     (let ((form (macroexpand (car body))))
	       (cond ((or (not (consp form))
			  (not (eq (car form) 'declare)))
		      (return (%bind-required lexp args (cadr lexp)
					      (%add-specials venv specials)
					      fenv benv genv args specials form body)))
		     (t (dolist (decl (cdar form))
			  (when (eq (car decl) 'special)
			    (setq specials
				  (if (null specials)	;Avoid consing
				      (cdar decl)
				      (append (cdar decl) specials))))))))))))

;;; %ADD-SPECIALS adds entries to VENV to account for SPECIAL declarations.

(defun %add-specials (venv specials)
  (do ((s specials (cdr s))
       (v venv (cons (list (car s)) v)))
      ((endp s) v)))

;;; %BIND-REQUIRED handles the pairing of arguments to required parameters.
;;; Error checking is performed for too few or too many arguments.
;;; If a lambda-list keyword is found, %TRY-OPTIONAL is called.
;;; Here, as elsewhere, if the binding process terminates satisfactorily
;;; then the body is evaluated using %EVPROGN in the newly constructed
;;; dynamic and lexical environment.

(defun %bind-required (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn form body venv fenv benv genv)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  lexp oldargs))))
	((not (symbolp (car varlist)))
	 (%bad-lambda-exp lexp oldargs "required parameter name not a symbol"))
	((%lambda-keyword-p (car varlist))
	 (%try-optional lexp oldargs varlist venv fenv benv genv args specials form body))
	((null args)
	 (%lambda-apply-retry lexp 
			      (cerror :too-few-arguments
				      "Too few arguments for function ~S: ~S"
				      lexp oldargs)))
	(t (%varbind (car varlist) (car args)
		      (%bind-required lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body)))))
!
;;; %TRY-OPTIONAL determines whether the lambda-list keyword &OPTIONAL
;;; has been found.  If so, optional parameters are processed; if not,
;;; the buck is passed to %TRY-REST.

(defun %try-optional (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&optional)
	 (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
	(t (%try-rest lexp oldargs varlist venv fenv benv genv args specials form body))))

;;; %BIND-OPTIONAL determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-optional (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn form body venv fenv benv genv)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  lexp oldargs))))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%try-rest lexp oldargs varlist venv fenv benv genv args specials form body)
			(%process-optional lexp oldargs varlist venv fenv benv
					   genv args specials form body varspec nil nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-optional lexp oldargs varlist venv fenv benv
				       genv args specials form body
				       (car varspec)
				       (cadr varspec)
				       (caddr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed optional parameter specifier")))))))

;;; %PROCESS-OPTIONAL takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-optional (lexp oldargs varlist venv fenv benv genv args specials form body var init varp)
  (let ((value (if (null args) (%eval init venv fenv benv genv) (car args))))
    (%varbind var value
      (if varp
	  (%varbind varp (not (null args))
	    (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body))
	  (%bind-optional lexp oldargs (cdr varlist) venv fenv benv genv (cdr args) specials form body)))))
!
;;; %TRY-REST determines whether the lambda-list keyword &REST
;;; has been found.  If so, the rest parameter is processed;
;;; if not, the buck is passed to %TRY-KEY, after a check for
;;; too many arguments.

(defun %try-rest (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&rest)
	 (%bind-rest lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
	((and (not (eq (car varlist) '&key))
	      (not (null args)))
	 (%lambda-apply-retry lexp
			      (cerror :too-many-arguments
				      "Too many arguments for function ~S: ~S"
				      lexp oldargs)))
	(t (%try-key lexp oldargs varlist venv fenv benv genv args specials form body))))

;;; %BIND-REST ensures that there is a parameter specifier for
;;; the &REST parameter, binds it, and then evaluates the body or
;;; calls %TRY-KEY.

(defun %bind-rest (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((or (endp varlist)
	     (not (symbolp (car varlist))))
	 (%bad-lambda-exp lexp oldargs "missing rest parameter specifier"))
	(t (%varbind (car varlist) args
	     (cond ((endp (cdr varlist))
		    (%lambda-evprogn form body venv fenv benv genv))
		   ((and (symbolp (cadr varlist))
			 (%lambda-keyword-p (cadr varlist)))
		    (%try-key lexp oldargs (cdr varlist) venv fenv benv genv args specials form body))
		   (t (%bad-lambda-exp lexp oldargs "malformed after rest parameter specifier")))))))
!
;;; %TRY-KEY determines whether the lambda-list keyword &KEY
;;; has been found.  If so, keyword parameters are processed;
;;; if not, the buck is passed to %TRY-AUX.

(defun %try-key (lexp oldargs varlist venv fenv benv genv args specials form body)
  (cond ((eq (car varlist) '&key)
	 (%bind-key lexp oldargs (cdr varlist) venv fenv benv genv args specials form body nil))
	(t (%try-aux lexp oldargs varlist venv fenv benv genv specials form body))))

;;; %BIND-KEY determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-key (lexp oldargs varlist venv fenv benv genv args specials form body keys)
  (cond ((endp varlist)
	 (%check-for-bad-keywords lexp args keys)
	 (%lambda-evprogn form body venv fenv benv genv))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(cond ((not (eq varspec '&allow-other-keywords))
			       (%check-for-bad-keywords lexp args keys)
			       (%try-aux lexp oldargs varlist venv fenv benv genv specials form body))
			      ((endp (cdr varlist))
			       (%lambda-evprogn form body venv fenv benv genv))
			      ((%lambda-keyword-p (cadr varlist))
			       (%try-aux lexp oldargs (cdr varlist) venv fenv benv genv specials form body))
			      (t (%bad-lambda-exp lexp oldargs "invalid after &ALLOW-OTHER-KEYWORDS")))
			(%process-key lexp oldargs varlist venv fenv benv
				      genv args specials form body keys
				      (intern (symbol-print-name varspec) keyword-package)
				      varspec nil nil)))
		   ((and (consp varspec)
			 (or (symbolp (car varspec))
			     (and (consp (car varspec))
				  (consp (cdar varspec))
				  (symbolp (cadar varspec))
				  (endp (cddar varspec))))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-key lexp oldargs varlist venv fenv benv
				  genv args specials form body keys
				  (if (consp (car varspec))
				      (caar varspec)
				      (intern (symbol-print-name (car varspec)) keyword-package))
				  (if (consp (car varspec))
				      (cadar varspec)
				      (car varspec))
				  (cadr varspec)
				  (caddr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed keyword parameter specifier")))))))

;;; Optional error check for bad keyword arguments.

(defun %check-for-bad-keywords (lexp args keys)
  (do ((a args (cddr a)))
      ((endp args))
    (unless (memq (car a) keys)
      (cerror :unexpected-keyword
	      "Keyword not expected by function ~S: ~S"
	      lexp (car a)))))

;;; %PROCESS-KEY takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-key (lexp oldargs varlist venv fenv benv genv args specials form body keys kwd var init varp)
  (do ((a args (cddr a)))
      ((endp a)
       (%process-key-1 lexp oldargs varlist venv fenv benv genv args specials
		       form body keys kwd var init varp
		       (%eval init venv fenv benv genv) nil))
    (when (eq (car a) kwd)
      (return (%process-key-1 lexp oldargs varlist venv fenv benv genv args specials
			      form body keys kwd var init varp
			      (cadr a) t)))))

(defun %process-key-1 (lexp oldargs varlist venv fenv benv genv args specials form body keys kwd var init varp value suppliedp)
  (%varbind var value
    (if varp
	(%varbind varp suppliedp
	  (%bind-key lexp oldargs varlist venv fenv benv genv args specials form body (cons kwd keys)))
	(%bind-key lexp oldargs varlist venv fenv benv genv args specials form body (cons kwd keys)))))
!
;;; %TRY-AUX determines whether the keyword &AUX
;;; has been found.  If so, auxiliary variables are processed;
;;; if not, an error is signalled.

(defun %try-aux (lexp oldargs varlist venv fenv benv genv specials form body)
  (cond ((eq (car varlist) '&aux)
	 (%bind-aux lexp oldargs (cdr varlist) venv fenv benv genv specials form body))
	(t (%bad-lambda-exp lexp oldargs "unknown or misplaced lambda-list keyword"))))

;;; %BIND-AUX determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-aux (lexp oldargs varlist venv fenv benv genv specials form body)
  (cond ((endp varlist)
	 (%lambda-evprogn form body venv fenv benv genv))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%bad-lambda-exp lexp oldargs "unknown or misplaced lambda-list keyword")
			(%process-aux lexp oldargs varlist venv fenv benv
				      genv specials form body varspec nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (endp (cddr varspec)))
		    (%process-aux lexp oldargs varlist venv fenv benv
				       genv specials form body
				       (car varspec)
				       (cadr varspec)))
		   (t (%bad-lambda-exp lexp oldargs "malformed aux variable specifier")))))))

;;; %PROCESS-AUX takes care of binding the auxiliary variable.

(defun %process-aux (lexp oldargs varlist venv fenv benv genv specials form body var init)
  (%varbind var (and init (%eval init venv fenv benv genv))
    (%bind-aux lexp oldargs varlist venv fenv benv genv specials form body)))

(defun %lambda-evprogn (form body venv fenv benv genv)
  (unless (null form) (%eval form venv fenv benv genv))
  (%evprogn body venv fenv benv genv))
!
;;; Definitions for various special forms and macros.

(defspec quote (obj) (venv fenv benv genv) obj)

(defspec function (fn) (venv fenv benv genv)
  (loop (cond ((consp fn)
	       (cond ((eq (car fn) 'lambda)
		      (return (make-interpreted-closure :function fn
							:venv venv
							:fenv fenv
							:benv benv
							:genv genv)))
		     (t (setq fn (cerror :invalid-function
					 "~S is not a valid argument for FUNCTION"
					 fn)))))
	      ((symbolp fn)
	       (let ((slot (assq fn fenv)))
		 (cond (slot
			(case (cadr slot)
			  (macro (setq fn (cerror :invalid-function
						  "The name ~S is invalid for FUNCTION: it names a macro"
						  fn)))
			  (function (return (cddr slot)))
			  (t <implementation-error>)))
		       ((fboundp fn)
			(cond ((special-form-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a special form"
						fn)))
			      ((macro-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a macro"
						fn)))
			      (t (setq fn (symbol-function fn)))))
		       (t (setq fn (cerror :invalid-function
					   "The symbol ~S has no function definition"
					   fn))))))
	      (t (setq fn (cerror :invalid-function
				  "~S is not a valid argument for FUNCTION"
				  fn))))))

(defspec if (pred con &optional alt) (venv fenv benv genv)
  (if (%eval pred venv fenv benv genv)
      (%eval con venv fenv benv genv)
      (%eval alt venv fenv benv genv)))

;;; The BLOCK construct provides a PROGN with a named contour around it.
;;; It is interpreted by first putting an entry onto BENV, consisting
;;; of a 1-list of the name.  This list cell serves as a catch tag.
;;; Then the body is executed.
;;; If a RETURN-FROM is interpreted, a throw occurs.  If the BLOCK
;;; construct is exited for any reason (including falling off the end, which
;;; returns the results of evaluating the last form in the body), the cdr of
;;; the entry is clobbered to be INVALID, to indicate that that particular
;;; entry is no longer valid for RETURN-FROM.

(defspec block (name &body body) (venv fenv benv genv)
  (let ((slot (list name)))
    (unwind-protect (catch slot
		      (%evprogn body venv fenv (cons slot benv) genv))
		    (rplacd slot 'invalid))))

(defspec return (form) (venv fenv benv genv)
  (let ((slot (assq nil benv)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form venv fenv benv genv))))))

(defspec return-from (name form) (venv fenv benv genv)
  (let ((slot (assq name benv)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form venv fenv benv genv))))))
!
(defmacro prog (vars &rest body)
  (do ((b body (cdr b))
       (decls '() (cons (car b) decls)))
      ((or (endp b)
	   (atom (car b))
	   (let ((x (macroexpand (car b))))
	     (or (atom x) (not (eq (car x) 'declare)))))
       `(let ,vars ,@(nreverse decls) (block nil (tagbody ,@b))))))

;;; The TAGBODY construct provides a body with GO tags in it.
;;; It is interpreted by first putting one entry onto GENV for
;;; every tag in the body; doing this ahead of time saves searching
;;; at GO time.  A unique cons whose car is NIL is constructed for
;;; use as a unique catch tag.  Then the body is executed.
;;; If a GO is interpreted, a throw occurs, sending as the thrown
;;; value the point in the body after the relevant tag.
;;; If the TAGBODY construct is exited for any reason (including
;;; falling off the end, which produces the value NIL), the car of
;;; the unique marker is clobbered to be INVALID, to indicate that
;;; tags associated with that marker are no longer valid.

(defspec tagbody (&rest body) (venv fenv benv genv)
  (do ((b body (cdr b))
       (marker (list nil)))
      ((endp p)
       (block exit
	 (unwind-protect
	  (loop (setq body
		      (catch marker
			(do ((b body (cdr b)))
			    ((endp b) (return-from exit nil))
			  (unless (atom (car b))
			    (%eval (car b) venv fenv benv genv))))))
	  (rplaca marker 'invalid))))
    (when (atom (car b))
      (push (list* (car b) marker (cdr b)) genv))))

(defspec go (tag) (venv fenv benv genv)
  (let ((slot (assq tag genv)))
    (cond ((null slot) (ferror ???<unseen-go-tag>))
	  ((eq (caadr slot) 'invalid) (ferror ???<go-tag-no-longer-valid>))
	  (t (throw (cadr slot) (cddr slot))))))
-------------------------------------------------------------
;;; This version uses some special variables to avoid passing stuff around.

;;; This evaluator splits the lexical environment into four
;;; logically distinct entities:
;;;	VENV = lexical variable environment
;;;	FENV = lexical function and macro environment
;;;	BENV = block name environment
;;;	GENV = go tag environment
;;; Each environment is an a-list.  It is never the case that
;;; one can grow and another shrink simultaneously; the four
;;; parts could be united into a single a-list.  The four-part
;;; division saves consing and search time.
;;;
;;; In this implementation, the four environment parts are normally
;;; kept in four special variables %VENV%, %FENV%, %BENV%, and %GENV%.
;;; (These are internal to the implementation, and are not meant to
;;; be user-accessible.)

(defvar %venv% nil)
(defvar %fenv% nil)
(defvar %benv% nil)
(defvar %genv% nil)

;;; Each entry in VENV has one of two forms: (VAR VALUE) or (VAR).
;;; The first indicates a lexical binding of VAR to VALUE, and the
;;; second indicates a special binding of VAR (implying that the
;;; special value should be used).
;;;
;;; Each entry in FENV looks like (NAME TYPE . FN), where NAME is the
;;; functional name, TYPE is either FUNCTION or MACRO, and FN is the
;;; function or macro-expansion function, respectively.  Entries of
;;; type FUNCTION are made by FLET and LABELS; those of type MACRO
;;; are made by MACROLET.
;;;
;;; Each entry in BENV looks like (NAME), where NAME is the name
;;; of the block.  The cons cell that is the entry is used as a
;;; catch tag for implementing RETURN-FROM.  If the entry has been
;;; clobbered to look like (NAME . INVALID), then the block has
;;; been exited, and a return to that block is an error.
;;;
;;; Each entry in GENV looks like (TAG MARKER . BODY), where TAG is
;;; a go tag, MARKER is a unique cons used as a catch tag, and BODY
;;; is the statement sequence that follows the go tag.  If the car of
;;; MARKER, normally NIL, has been clobbered to be INVALID, then
;;; the tag body has been exited, and a go to that tag is an error.

;;; An interpreted-lexical-closure contains a function (normally a
;;; lambda-expression) and the lexical environment.

(defstruct interpreted-lexical-closure function venv fenv benv genv)


;;; The EVALHOOK feature allows a user-supplied function to be called
;;; whenever a form is to be evaluated.  The presence of the lexical
;;; environment requires an extension of the feature as it is defined
;;; in MacLISP.  Here, the user hook function must accept not only
;;; the form to be evaluated, but also the components of the lexical
;;; environment; these must then be passed verbatim to EVALHOOK or
;;; *EVAL in order to perform the evaluation of the form correctly.
;;; The precise number of components should perhaps be allowed to be
;;; implementation-dependent, so it is probably best to require the
;;; user hook function to accept arguments as (FORM &REST ENV) and
;;; then to perform evaluation by (APPLY #'EVALHOOK FORM HOOKFN ENV),
;;; for example.

(defvar *evalhook* nil)

(defun evalhook (exp hookfn %venv% %fenv% %benv% %genv%)
  (let ((*evalhook* hookfn))
	(%eval1 exp)))

(defun eval (exp)
  (*eval exp nil nil nil nil))

(defun *eval (exp %venv% %fenv% %benv% %genv%)
  (%eval exp))
!
;;; Function names beginning with "%" are intended to be internal
;;; and not defined in the Common LISP white pages.

;;; %EVAL is the main evaluation function.  It is split into two
;;; parts, with the main part called %EVAL1, for the benefit of EVALHOOK.
;;; It evaluates EXP in the current lexical environment, assumed to be
;;; in %VENV%, %FENV%, %BENV%, and %GENV%.

(defun %eval (exp)
  (if *evalhook*
      (let ((hookfn *evalhook*) (*evalhook* nil))
	(funcall hookfn exp %venv% %fenv% %benv% %genv%))
      (t (%eval1 exp))))

(defun %eval1 (exp)
  (typecase exp
    ;; A symbol is first looked up in the lexical variable environment.
    (symbol (let ((slot (assq exp %venv%)))
	      (cond ((and slot (not (null (cdr slot))))
		     (cadr slot))
		    ((boundp exp) (symbol-value exp))
		    (t (cerror :unbound-variable
			       "The symbol ~S has no value"
			       exp)))))
    ;; Numbers, strings, bit-vectors, and characters self-evaluate.
    ((or number string bit-vector character) exp)
    ;; Conses require elaborate treatment based on the car.
    (cons (typecase (car exp)
	    ;; A symbol is first looked up in the lexical function environment.
	    ;; This lookup is cheap if the environment is empty, a common case.
	    (symbol
	     (let ((fn (car exp)))
	       (loop (let ((slot (assq fn %fenv%)))
		       (unless (null slot)
			 (return (case (cadr slot)
				   (macro (%eval (%macroexpand
						  (cddr slot)
						  (if (eq fn (car exp))
						      exp
						      (cons fn (cdr exp))))))
				   (function (%apply (cddr slot)
						     (%evlis (cdr exp))))
				   (t <implementation-error>)))))
		     ;; If not in lexical function environment,
		     ;;  try the definition cell of the symbol.
		     (when (fboundp fn)
		       (return (cond ((special-form-p fn)
				      (%invoke-special-form fn (cdr exp)))
				     ((macro-p fn)
				      (%eval (%macroexpand
					      (get-macro-function (symbol-function fn))
					      (if (eq fn (car exp))
						  exp
						  (cons fn (cdr exp))))))
				     (t (%apply (symbol-function fn)
						(%evlis (cdr exp)))))))
		     (setq fn
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
		     (unless (symbolp fn)
		       (return (%apply fn (%evlis (cdr exp))))))))
	    ;; A cons in function position must be a lambda-expression.
	    ;; Note that the construction of a lexical closure is avoided here.
	    (cons (apply (car exp) (%evlis (cdr exp))))
	    (t (%eval (cerror :invalid-form
			      "Cannot evaluate the form ~S: function position has invalid type ~S"
			      exp (type-of (car exp)))))))
    (t (%eval (cerror :invalid-form
		      "Cannot evaluate the form ~S: invalid type ~S"
		      exp (type-of exp))))))
!
;;; Given a list of forms, evaluate each and return a list of results.

(defun %evlis (forms)
  (mapcar #'(lambda (form) (%eval form)) forms))

;;; Given a list of forms, evaluate each, discarding the results of
;;; all but the last, and returning all results from the last.

(defun %evprogn (body)
  (if (endp body) nil
      (do ((b body (cdr b)))
	  ((endp (cdr b))
	   (%eval (car b)))
	(%eval (car b)))))

;;; APPLY takes a function, a number of single arguments, and finally
;;; a list of all remaining arguments.  The following song and dance
;;; attempts to construct efficiently a list of all the arguments.

(defun apply (fn firstarg &rest args*)
  (let ((%venv% nil) (%fenv% nil) (%benv% nil) (%genv% nil))
    (%apply fn
	    (cond ((null args*) firstarg)
		  ((null (cdr args*)) (cons firstarg (car args*)))
		  (t (do ((x args* (cdr x))
			  (z (cddr args*) (cdr z)))
			 ((null z)
			  (rplacd x (cadr x))
			  (cons firstarg (car args*)))))))))
!
;;; %APPLY does the real work of applying a function to a list of arguments.

(defun %apply (fn args)
  (typecase fn
    ;; For a compiled function, an implementation-dependent "spread"
    ;;  operation and invocation is required.
    (compiled-function (%invoke-compiled-function fn args))
    ;; The same goes for a compiled closure over lexical variables.
    (compiled-lexical-closure (%invoke-compiled-lexical-closure fn args))
    ;; The treatment of interpreted lexical closures is elucidated fully here.
    (interpreted-lexical-closure
     (let ((%venv% (interpreted-lexical-closure-venv fn))
	   (%fenv% (interpreted-lexical-closure-fenv fn))
	   (%benv% (interpreted-lexical-closure-benv fn))
	   (%genv% (interpreted-lexical-closure-genv fn)))
       (%lambda-apply (interpreted-lexical-closure-function fn) args)))
    ;; For a symbol, the function definition is used, if it is a function.
    (symbol (%apply (cond ((not (fboundp fn))
			   (cerror :undefined-function
				   "The symbol ~S has no function definition"
				   fn))
			  ((special-form-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a special form"
				   fn))
			  ((macro-p fn)
			   (cerror :invalid-function
				   "The symbol ~S cannot be applied: it names a macro"
				   fn))
			  (t (symbol-function fn)))
		    args))
    (cons (if (eq (car fn) 'lambda)
	      (%lambda-apply fn args)
	      (%apply (cerror :invalid-function
			      "~S is not a valid function"
			      fn)
		      args)))
    (t (%apply (cerror :invalid function
		       "~S has an invalid type ~S for a function"
		       fn (type-of fn))
	       args))))
!
;;; %LAMBDA-APPLY is the hairy part, that takes care of applying
;;; a lambda-expression in a given lexical environment to given
;;; arguments.  The complexity arises primarily from the processing
;;; of the parameter list.
;;;
;;; If at any point the lambda-expression is found to be malformed
;;; (typically because of an invalid parameter list), or if the list
;;; of arguments is not suitable for the lambda-expression, a correctable
;;; error is signalled; correction causes a throw to be performed to
;;; the tag %LAMBDA-APPLY-RETRY, passing back a (possibly new)
;;; lambda-expression and a (possibly new) list of arguments.
;;; The application is then retried.  If the new lambda-expression
;;; is not really a lambda-expression, then %APPLY is used instead of
;;; %LAMBDA-APPLY.
;;;
;;; In this evaluator, PROGV is used to instantiate variable bindings
;;; (though its use is embedded with a macro called %varbind).
;;; The throw that precedes a retry will cause special bindings to
;;; be popped before the retry.

(defun %lambda-apply (lexp args)
  (multiple-value-bind (newfn newargs)
		       (catch '%lambda-apply-retry
			 (return-from %lambda-apply
			   (let ((%venv% %venv%))
			     (%lambda-apply-1 lexp args))))
    (if (and (consp newfn) (eq (car newfn) 'lambda))
	(%lambda-apply newfn newargs)
	(%apply newfn newargs))))

;;; Calling this function will unwind all special variables
;;; and cause FN to be applied to ARGS in the original lexical
;;; and dynamic environment in force when %LAMBDA-APPLY was called.

(defun %lambda-apply-retry (fn args)
  (throw '%lambda-apply-retry (values fn args)))

(defvar %lexp%)
(defvar %oldargs%)

;;; This function is convenient when the lambda expression is found
;;; to be malformed.  REASON should be a string explaining the problem.

(defun %bad-lambda-exp (reason)
  (%lambda-apply-retry
   (cerror :invalid-function
	   "Improperly formed lambda-expression ~S: ~A"
	   %lexp% reason)
   %oldargs%))

;;; (%varbind VAR VALUE . BODY) evaluates VAR to produce a symbol name
;;; and VALUE to produce a value.  If VAR is determined to have been
;;; declared special (as indicated by the current binding of the variable
;;; SPECIALS, which should be a list of symbols, or by a SPECIAL property),
;;; then a special binding is established using PROGV.  Otherwise an
;;; entry is pushed onto the a-list presumed to be in the variable VENV.

;;; The CONSTANTP test ideally is true for any constant symbol;
;;; it should at least check for T, NIL, and keywords.

(defmacro %varbind (var value &body body)
  (let ((xvar (gensym)) (xvalue (gensym)))
    `(let ((,xvar ,var) (,xvalue ,value))
       (loop (when (not (constantp ,xvar)) (return))
	     (setq ,xvar (cerror :invalid-variable
				 "~S is a constant and may not be bound"
				 ,xvar)))
       (let ((specp (or (memq ,xvar %specials%) (get ,xvar 'special))))
	 (progv (and specp (list ,xvar)) (and specp (list ,xvalue))
		(unless specp (push (list ,xvar ,xvalue) venv))
		,@body)))))

;;; %LAMBDA-KEYWORD-P is true iff X (which must be a symbol)
;;; has a name beginning with an ampersand.

(defun %lambda-keyword-p (x)
  (char= #\& (char 0 (symbol-pname x))))
!
;;; %LAMBDA-APPLY-1 is responsible for verifying that LEXP is
;;; a lambda-expression, for extracting a list of all variables
;;; declared SPECIAL in DECLARE forms, and for finding the
;;; body that follows any DECLARE forms.

(defvar %specials%)
(defvar %form%)
(defvar %body%)

(defun %lambda-apply-1 (%lexp% %oldargs%)
  (cond ((or (not (consp %lexp%))
	     (not (eq (car %lexp%) 'lambda))
	     (atom (cdr %lexp%))
	     (not (listp (cadr %lexp%))))
	 (%bad-lambda-exp "improper lambda-expression"))
	(t (do ((%body% (cddr %lexp%) (cdr %body%))
		(%specials% '()))
	       ((or (endp %body%)
		    (not (listp (car %body%))))
		(let ((%form% nil))
		  (%add-specials)
		  (%bind-required (cadr %lexp%) %oldargs%)))
	     (let ((%form% (macroexpand (car %body%))))
	       (cond ((or (not (consp %form%))
			  (not (eq (car %form%) 'declare)))
		      (%add-specials)
		      (return (%bind-required (cadr %lexp%) %oldargs%)))
		     (t (dolist (decl (cdr %form%))
			  (when (eq (car decl) 'special)
			    (setq %specials%
				  (if (null %specials%)	;Avoid consing
				      (cdar decl)
				      (append (cdar decl) %specials%))))))))))))

;;; %ADD-SPECIALS adds entries to VENV to account for SPECIAL declarations.

(defun %add-specials ()
  (dolist (s %specials%)
    (push (list s) %venv%)))

;;; %BIND-REQUIRED handles the pairing of arguments to required parameters.
;;; Error checking is performed for too few or too many arguments.
;;; If a lambda-list keyword is found, %TRY-OPTIONAL is called.
;;; Here, as elsewhere, if the binding process terminates satisfactorily
;;; then the body is evaluated using %EVPROGN in the newly constructed
;;; dynamic and lexical environment.

(defun %bind-required (varlist args)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn%)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  %lexp% %oldargs%))))
	((not (symbolp (car varlist)))
	 (%bad-lambda-exp "required parameter name not a symbol"))
	((%lambda-keyword-p (car varlist))
	 (%try-optional varlist args))
	((null args)
	 (%lambda-apply-retry lexp 
			      (cerror :too-few-arguments
				      "Too few arguments for function ~S: ~S"
				      %lexp% %oldargs%)))
	  (t (%varbind (car varlist) (car args)
			(%bind-required (cdr varlist) (cdr args))))))
!
;;; %TRY-OPTIONAL determines whether the lambda-list keyword &OPTIONAL
;;; has been found.  If so, optional parameters are processed; if not,
;;; the buck is passed to %TRY-REST.

(defun %try-optional (varlist args)
  (cond ((eq (car varlist) '&optional)
	 (%bind-optional (cdr varlist) args))
	(t (%try-rest varlist args))))

;;; %BIND-OPTIONAL determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-optional (varlist args)
  (cond ((endp varlist)
	 (if (null args)
	     (%lambda-evprogn%)
	     (%lambda-apply-retry lexp
				  (cerror :too-many-arguments
					  "Too many arguments for function ~S: ~S"
					  %lexp% %oldargs%))))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%try-rest varlist args)
			(%process-optional varlist args varspec nil nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-optional varlist args
				       (car varspec)
				       (cadr varspec)
				       (caddr varspec)))
		   (t (%bad-lambda-exp "malformed optional parameter specifier")))))))

;;; %PROCESS-OPTIONAL takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-optional (varlist args var init varp)
  (let ((value (if (null args) (%eval init) (car args))))
    (%varbind var value
      (if varp
	  (%varbind varp (not (null args))
	    (%bind-optional (cdr varlist) (cdr args)))
	  (%bind-optional (cdr varlist) (cdr args))))))
!
;;; %TRY-REST determines whether the lambda-list keyword &REST
;;; has been found.  If so, the rest parameter is processed;
;;; if not, the buck is passed to %TRY-KEY, after a check for
;;; too many arguments.

(defun %try-rest (varlist args)
  (cond ((eq (car varlist) '&rest)
	 (%bind-rest (cdr varlist) args))
	((and (not (eq (car varlist) '&key))
	      (not (null args)))
	 (%lambda-apply-retry lexp
			      (cerror :too-many-arguments
				      "Too many arguments for function ~S: ~S"
				      %lexp% %oldargs%)))
	(t (%try-key varlist args))))

;;; %BIND-REST ensures that there is a parameter specifier for
;;; the &REST parameter, binds it, and then evaluates the body or
;;; calls %TRY-KEY.

(defun %bind-rest (varlist args)
  (cond ((or (endp varlist)
	     (not (symbolp (car varlist))))
	 (%bad-lambda-exp "missing rest parameter specifier"))
	(t (%varbind (car varlist) args
	     (cond ((endp (cdr varlist))
		    (%lambda-evprogn%))
		   ((and (symbolp (cadr varlist))
			 (%lambda-keyword-p (cadr varlist)))
		    (%try-key (cdr varlist) args))
		   (t (%bad-lambda-exp "malformed after rest parameter specifier")))))))
!
;;; %TRY-KEY determines whether the lambda-list keyword &KEY
;;; has been found.  If so, keyword parameters are processed;
;;; if not, the buck is passed to %TRY-AUX.

(defun %try-key (varlist args)
  (cond ((eq (car varlist) '&key)
	 (%bind-key (cdr varlist) args nil))
	(t (%try-aux varlist))))

;;; %BIND-KEY determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-key (varlist args keys)
  (cond ((endp varlist)
	 (%check-for-bad-keywords args keys)
	 (%lambda-evprogn%))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(cond ((not (eq varspec '&allow-other-keywords))
			       (%check-for-bad-keywords args keys)
			       (%try-aux varlist))
			      ((endp (cdr varlist))
			       (%lambda-evprogn%))
			      ((%lambda-keyword-p (cadr varlist))
			       (%try-aux (cdr varlist)))
			      (t (%bad-lambda-exp "invalid after &ALLOW-OTHER-KEYWORDS")))
			(%process-key varlist args keys
				      (intern (symbol-print-name varspec) keyword-package)
				      varspec nil nil)))
		   ((and (consp varspec)
			 (or (symbolp (car varspec))
			     (and (consp (car varspec))
				  (consp (cdar varspec))
				  (symbolp (cadar varspec))
				  (endp (cddar varspec))))
			 (listp (cdr varspec))
			 (or (endp (cddr varspec))
			     (and (symbolp (caddr varspec))
				  (not (endp (caddr varspec)))
				  (endp (cdddr varspec)))))
		    (%process-key varlist args keys
				  (if (consp (car varspec))
				      (caar varspec)
				      (intern (symbol-print-name (car varspec)) keyword-package))
				  (if (consp (car varspec))
				      (cadar varspec)
				      (car varspec))
				  (cadr varspec)
				  (caddr varspec)))
		   (t (%bad-lambda-exp "malformed keyword parameter specifier")))))))

;;; Optional error check for bad keywords.

(defun %check-for-bad-keywords (args keys)
  (do ((a args (cddr a)))
      ((endp args))
    (unless (memq (car a) keys)
      (cerror :unexpected-keyword
	      "Keyword not expected by function ~S: ~S"
	      %lexp% (car a)))))

;;; %PROCESS-KEY takes care of binding the parameter,
;;; and also the supplied-p variable, if any.

(defun %process-key (varlist args keys kwd var init varp)
  (do ((a args (cddr a)))
      ((endp a)
       (%process-key-1 varlist args keys kwd var init varp (%eval init) nil))
    (when (eq (car a) kwd)
      (return (%process-key-1 varlist args keys kwd var init varp (cadr a) t)))))

(defun %process-key-1 (varlist args keys kwd var init varp value suppliedp)
  (%varbind var value
    (if varp
	(%varbind varp suppliedp
	  (%bind-key varlist args (cons kwd keys)))
	(%bind-key varlist args (cons kwd keys)))))
!
;;; %TRY-AUX determines whether the keyword &AUX
;;; has been found.  If so, auxiliary variables are processed;
;;; if not, an error is signalled.

(defun %try-aux (varlist)
  (cond ((eq (car varlist) '&aux)
	 (%bind-aux (cdr varlist)))
	(t (%bad-lambda-exp "unknown or misplaced lambda-list keyword"))))

;;; %BIND-AUX determines whether the parameter list is exhausted.
;;; If not, it parses the next specifier.

(defun %bind-aux (varlist)
  (cond ((endp varlist)
	 (%lambda-evprogn%))
	(t (let ((varspec (car varlist)))
	     (cond ((symbolp varspec)
		    (if (%lambda-keyword-p varspec)
			(%bad-lambda-exp "unknown or misplaced lambda-list keyword")
			(%process-aux varlist varspec nil)))
		   ((and (consp varspec)
			 (symbolp (car varspec))
			 (listp (cdr varspec))
			 (endp (cddr varspec)))
		    (%process-aux varlist (car varspec) (cadr varspec)))
		   (t (%bad-lambda-exp "malformed aux variable specifier")))))))

;;; %PROCESS-AUX takes care of binding the auxiliary variable.

(defun %process-aux (varlist var init)
    (%varbind var (and init (%eval init))
       (%bind-aux varlist)))

(defun %lambda-evprogn ()
  (unless (null %form%) (%eval %form%))
  (%evprogn %body%))
!
;;; Definitions for various special forms and macros.

(defspec quote (obj) obj)

(defspec function (fn)
  (loop (cond ((consp fn)
	       (cond ((eq (car fn) 'lambda)
		      (return (make-interpreted-closure :function fn
							:venv %venv%
							:fenv %fenv%
							:benv %benv%
							:genv %genv%)))
		     (t (setq fn (cerror :invalid-function
					 "~S is not a valid argument for FUNCTION"
					 fn)))))
	      ((symbolp fn)
	       (let ((slot (assq fn fenv)))
		 (cond (slot
			(case (cadr slot)
			  (macro (setq fn (cerror :invalid-function
						  "The name ~S is invalid for FUNCTION: it names a macro"
						  fn)))
			  (function (return (cddr slot)))
			  (t <implementation-error>)))
		       ((fboundp fn)
			(cond ((special-form-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a special form"
						fn)))
			      ((macro-p fn)
			       (setq fn (cerror :invalid-function
						"The symbol ~S is invalid for FUNCTION: it names a macro"
						fn)))
			      (t (setq fn (symbol-function fn)))))
		       (t (setq fn (cerror :invalid-function
					   "The symbol ~S has no function definition"
					   fn))))))
	      (t (setq fn (cerror :invalid-function
				  "~S is not a valid argument for FUNCTION"
				  fn))))))

(defspec if (pred con &optional alt)
  (if (%eval pred) (%eval con) (%eval alt)))

;;; The BLOCK construct provides a PROGN with a named contour around it.
;;; It is interpreted by first putting an entry onto BENV, consisting
;;; of a 1-list of the name.  This list cell serves as a catch tag.
;;; Then the body is executed.
;;; If a RETURN-FROM is interpreted, a throw occurs.  If the BLOCK
;;; construct is exited for any reason (including falling off the end, which
;;; returns the results of evaluating the last form in the body), the cdr of
;;; the entry is clobbered to be INVALID, to indicate that that particular
;;; entry is no longer valid for RETURN-FROM.

(defspec block (name &body body)
  (let ((slot (list name)))
    (unwind-protect (catch slot
		      (let ((%benv% (cons slot %benv%)))
			(%evprogn body)))
		    (rplaca (cdr slot) 'invalid))))

(defspec return (form)
  (let ((slot (assq nil %benv%)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form))))))

(defspec return-from (name form)
  (let ((slot (assq name %benv%)))
    (cond ((null slot) (ferror ???<unseen-block-name>))
	  ((eq (cdr slot) 'invalid) (ferror ???<block-name-no-longer-valid>))
	  (t (throw slot (%eval form))))))
!
(defmacro prog (vars &rest body)
  (do ((b body (cdr b))
       (decls '() (cons (car b) decls)))
      ((or (endp b)
	   (atom (car b))
	   (let ((x (macroexpand (car b))))
	     (or (atom x) (not (eq (car x) 'declare)))))
       `(let ,vars ,@(nreverse decls) (block nil (tagbody ,@b))))))

;;; The TAGBODY construct provides a body with GO tags in it.
;;; It is interpreted by first putting one entry onto GENV for
;;; every tag in the body; doing this ahead of time saves searching
;;; at GO time.  A unique cons whose car is NIL is constructed for
;;; use as a unique catch tag.  Then the body is executed.
;;; If a GO is interpreted, a throw occurs, sending as the thrown
;;; value the point in the body after the relevant tag.
;;; If the TAGBODY construct is exited for any reason (including
;;; falling off the end, which produces the value NIL), the car of
;;; the unique marker is clobbered to be INVALID, to indicate that
;;; tags associated with that marker are no longer valid.

(defspec tagbody (&rest body)
  (let ((%genv% %genv%))
    (do ((b body (cdr b))
	 (marker (list nil)))
	((endp p)
	 (block exit
	   (unwind-protect
	    (loop (setq body
			(catch marker
			  (do ((b body (cdr b)))
			      ((endp b) (return-from exit nil))
			    (unless (atom (car b))
			      (%eval (car b)))))))
	    (rplaca marker 'invalid))))
      (when (atom (car b))
	(push (list* (car b) marker (cdr b)) %genv%)))))

(defspec go (tag)
  (let ((slot (assq tag %genv%)))
    (cond ((null slot) (ferror ???<unseen-go-tag>))
	  ((eq (caadr slot) 'invalid) (ferror ???<go-tag-no-longer-valid>))
	  (t (throw (cadr slot) (cddr slot))))))
-------

∂13-Nov-82  0118	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	#,  
Date: Saturday, 13 November 1982, 04:16-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: #,
To: Earl A. Killian <Killian at MIT-MULTICS>
Cc: common-lisp at SU-AI
In-reply-to: The message of 12 Nov 82 13:21-EST from Earl A. Killian <Killian at MIT-MULTICS>

    Date:     12 November 1982 1021-pst
    From:     Earl A. Killian            <Killian at MIT-MULTICS>

    Shouldn't #, be a reader abbreviations for some form just like ' is?
    Otherwise, how do you have a macro that uses the load-time-eval facility
    for constructed code?

We use (CONS COMPILER:EVAL-AT-LOAD-TIME-MARKER form) for this.  There is
absolutely nothing special or good about the name (other than that it is
better than calling it SQUID).  Speaking of primitives, Common Lisp also
prevents the user from writing the #, macro himself by not providing a way
to tell whether you are reading normally, or reading forms to be compiled
into a file that will later be loaded into another environment.

∂13-Nov-82  0232	Kent M. Pitman <KMP at MIT-MC> 	#, 
Date: 13 November 1982 05:32-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  #,
To: Killian at MIT-MULTICS
cc: common-lisp at SU-AI

jmc - Of your message of 0232, 13 Nov., copying common-lisp, only the header
made it.
∂13-Nov-82  1044	JONL at PARC-MAXC 	Re: Named lambdas    
Date: 13 NOV 1982 1040-PST
From: JONL at PARC-MAXC
Subject: Re: Named lambdas
To:   Fahlman at CMU-20C, Masinter
cc:   common-lisp at SU-AI, JONL

In response to the message sent  Thursday, 11 November 1982  11:54-EST from Fahlman@Cmu-20c

I thought so.  Why not eliminate another proliferation of mindless
primitives, NAMED-LAMBDA, and just have DEFUN etc insert
a "commentary" in a local declaration.  For example,
    (DEFUN FOO (X) (LIST X))
becomes something like
    (SI:DEFEXPR 'FOO '(LAMBDA (X) (DECLARE (NAME FOO)) (LIST X)))

This "DECLARE" syntax is Interlisp's and MacLisp's, but no
objection to this way of nameing should be entertained on
the basis of local declaration syntax.

∂13-Nov-82  1128	Scott E. Fahlman <Fahlman at Cmu-20c> 	Named lambdas   
Date: Saturday, 13 November 1982  14:27-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   JONL at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Named lambdas
In-reply-to: The message of 13 Nov 1982  13:40-EST from JONL at PARC-MAXC


The SI:DEFEXPR business confused me for awhile, but your basic
suggestion of hiding the name of the function in a declaration looks
good.  This would eliminate any need for NAMED-LAMBDA.  It might be
worthwhile to create a standard declaration form ("NAME" or
"FUNCTION-NAME" looks OK to me) to hold this sort of thing and explain
what it's for.  We already have the machinery to ignore declarations, so
this should add minimal new hair to any implementation.

-- Scott

∂13-Nov-82  1147	JONL at PARC-MAXC 	Re: Named lambdas    
Date: 13 NOV 1982 1148-PST
From: JONL at PARC-MAXC
Subject: Re: Named lambdas
To:   Fahlman at CMU-20C
cc:   common-lisp at SU-AI, JONL

In response to your message sent  Saturday, 13 November 1982  14:27-EST

Sorry for not making it more clear -- SI:DEFEXPR was just a
meta-name intended to imply it's action.

∂13-Nov-82  1516	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	Re: Named lambdas  
Date: Saturday, 13 November 1982, 18:11-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: Re: Named lambdas
To: Common-Lisp at SU-AI
In-reply-to: The message of 13 Nov 82 13:40-EST from JONL at PARC-MAXC

    Date: 13 NOV 1982 1040-PST
    From: JONL at PARC-MAXC

    Why not eliminate another proliferation of mindless
    primitives, NAMED-LAMBDA, and just have DEFUN etc insert
    a "commentary" in a local declaration.

This is a good idea, provided that there is a primitive defined to
extract the name buried in the declaration buried in the lambda.  It's
called SYS:FUNCTION-NAME in the Lisp machine; no really strong reason
why it isn't global.

If the Lisp machine LOCAL-DECLARATIONS mechanism were adopted, this would
also answer the other request for a way for macros to find out what function
they were inside, since they would do (CADR (ASSQ 'NAME LOCAL-DECLARATIONS)),
mutatis mutandis.

∂13-Nov-82  1950	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	implementing multiple values 
Date: Saturday, 13 November 1982, 22:42-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: implementing multiple values
To: Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>
Cc: common-lisp at SU-AI
In-reply-to: The message of 13 Nov 82 21:17-EST from Mgr DEC-20s/Dir LCSR Comp Facility <HEDRICK at RUTGERS>

    Date: 13 Nov 1982 2117-EST
    From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)

    E.g. consider the following example from Maclisp:
    (multiple-value-list (progn (values 'a 'b 'c) nil)) --> (nil b c)

Certainly the only sane and rational definition is that returning one
value by traditional Lisp and returning one value by using VALUES with
one argument must do the same thing.  The Maclisp implementation of
multiple values is broken; this is because it was kludged into an existing
implementation as a set of macros.

    It seems fairly clear that this should return either (nil) or (a b c).

The former.

    Probably the last two definitions are going to require that every
    value computation will interact with the m.v. mechanism, an overhead
    I would like to avoid.

Certainly.  But there is no run-time overhead, there is only the overhead of
making the interpreter and the compiler understand multiple values, rather
than kludging them in on top.

    (defun foo nil (values a b c))
    (defun bar nil (foo))
    (defun baz nil (multiple-value-list (bar]

(foo) and (bar) return the same 3 values, (baz) returns a list of them.

    (defun baz nil (multiple-value-list
		     (cond ((moon-phase) (foo))
			   (t  (trunc 5 2]

(baz) returns a different number of values depending on the predicate.

    (defun bar nil (cond ((moon-phase) (foo))
			 (t (trunc 5 2]
    (defun baz nil (multiple-value-list (bar]

This is the same as the previous example.

    (defun baz nil (multiple-value-list (progn (foo]

progn makes no difference.

    (defun baz nil (multiple-value-list (progn (foo) nil]

This returns a list of one element, NIL, of course.

You left out the only case that isn't obvious, namely

    (prog1 (foo) (bleagh))

I believe the current c.l. definition is that this returns one value, a,
and multiple-value-prog1 also exists and returns three values.


Maybe it would be instructive to look at how the Lisp machines (both of
them) implement multiple values.  Although these are machines specially
microcoded for Lisp, there is nothing microcode-dependent about this.
There is no extra overhead when multiple values are not being used.

When a function is called by a multiple value receiving form, a bit is
set somewhere in the stack frame.  This bit is in a place that gets
cleared for free when a function is called expecting only one value.
When a function is called tail-recursively, another bit is set.  When a
single value is returned from a function, these bits can be ignored.
When multiple values are returned, the microcode for that (and it could
just as well be a run-time support routine) follows back through
tail-recursive calls until it reaches the guy who is going to receive
the values, then checks his bit to see whether he wants multiple values.
If so, all the values are returned; if not, only the first value is
returned.

In practice there are some complexities about just where the values sit
while the stack is being unwound.  But these don't affect the semantics,
depend on implementation details, and in fact differ between the "A" and
"L" varieties of Lisp machines.  On a machine with enough general registers,
such as the pdp-10 or the VAX, you would probably put the values there.

Function-calling takes care of all cases of multiple values.  In the
interpreter, the function is always EVAL.  In compiled code, if the <form>
argument to MULTIPLE-VALUE or MULTIPLE-VALUE-BIND does not compile into
a function call, the compiler expands out the multiple value passing.
Thus (MULTIPLE-VALUE-BIND (A B C) (VALUES D E F) body) is just LET.

∂13-Nov-82  2158	Kim.fateman@Berkeley 	multiple-value return  
Date: 13-Nov-82 21:33:35-PST (Sat)
From: Kim.fateman@Berkeley
Subject: multiple-value return
Message-Id: <8210140532.2906@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A02900; 13-Nov-82 21:32:36-PST (Sat)
To: common-lisp@su-ai

It seems to me that the costs associated with doing this right can be
absorbed as Moon suggests, in microcode, but I am not convinced that the
costs can be easily borne in conventional machines.  Ordinarily a receiver
of a value will not know whether it must extract the first item in a multiple
value, or just use the non-multiple-value as given, unless some check
is performed.

What is the point of all this?  I see two points:  one: a minor convenience
for functions like divide (returning quotient and remainder), and its ilk
[its ilk growing extremely rapidly when hackers realize they can do this
free]; two: an important feature of a lisp where conses must be avoided.
Lisp Machines, esp. without garbage collectors, presumably benefit from the
avoidance of conses.  Lisps which must serve as system programming
languages (instead of using, say, C, which deals with call-by-reference
by the obvious kind of mechanism), is another possibility.

Let us turn the table a bit.  I believe that if conses/gc were really cheap,
there would be much less benefit to m-v-r.
e.g. divide could just return (quotient . remainder), other objects could
be cons'd up  (or put in vectors ...).  Now on conventional computers,
conses and gcs may not actually be so cheap, but if m-v-r is expensive,
perhaps conses WOULD be more acceptable? 

The constant overhead looking
for m-v-r in, for example, macsyma, which does not, at the moment, 
use m-v-r even once, would be distasteful. 

If m-v-r is free, of course, I suppose that's fine.  If it is not free,
perhaps it should be flushed from Common Lisp.

∂13-Nov-82  2207	Kim.fateman@Berkeley 	multiple-value return  
Date: 13-Nov-82 21:33:35-PST (Sat)
From: Kim.fateman@Berkeley
Subject: multiple-value return
Message-Id: <8210140532.2906@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A02900; 13-Nov-82 21:32:36-PST (Sat)
To: common-lisp@su-ai

It seems to me that the costs associated with doing this right can be
absorbed as Moon suggests, in microcode, but I am not convinced that the
costs can be easily borne in conventional machines.  Ordinarily a receiver
of a value will not know whether it must extract the first item in a multiple
value, or just use the non-multiple-value as given, unless some check
is performed.

What is the point of all this?  I see two points:  one: a minor convenience
for functions like divide (returning quotient and remainder), and its ilk
[its ilk growing extremely rapidly when hackers realize they can do this
free]; two: an important feature of a lisp where conses must be avoided.
Lisp Machines, esp. without garbage collectors, presumably benefit from the
avoidance of conses.  Lisps which must serve as system programming
languages (instead of using, say, C, which deals with call-by-reference
by the obvious kind of mechanism), is another possibility.

Let us turn the table a bit.  I believe that if conses/gc were really cheap,
there would be much less benefit to m-v-r.
e.g. divide could just return (quotient . remainder), other objects could
be cons'd up  (or put in vectors ...).  Now on conventional computers,
conses and gcs may not actually be so cheap, but if m-v-r is expensive,
perhaps conses WOULD be more acceptable? 

The constant overhead looking
for m-v-r in, for example, macsyma, which does not, at the moment, 
use m-v-r even once, would be distasteful. 

If m-v-r is free, of course, I suppose that's fine.  If it is not free,
perhaps it should be flushed from Common Lisp.

∂13-Nov-82  2355	David A. Moon <Moon at SCRC-TENEX at MIT-MC> 	multiple-value return   
Date: Sunday, 14 November 1982, 02:52-EST
From: David A. Moon <Moon at SCRC-TENEX at MIT-MC>
Subject: multiple-value return
To: Kim.fateman at UCB-C70
Cc: common-lisp at su-ai
In-reply-to: <8210140532.2906@UCBVAX.BERKELEY.ARPA>

    Date: 13-Nov-82 21:33:35-PST (Sat)
    From: Kim.fateman@Berkeley

    It seems to me that the costs associated with doing this right can be
    absorbed as Moon suggests, in microcode, but I am not convinced that the
    costs can be easily borne in conventional machines.  Ordinarily a receiver
    of a value will not know whether it must extract the first item in a multiple
    value, or just use the non-multiple-value as given, unless some check
    is performed.

Too bad you didn't read my message, which said not that costs can be absorbed
in microcode, but that there is absolutely nothing about the Lisp machine
implementation of multiple values that is dependent on having microcode
(unlike other Lisp machine features, invisible pointers for instance).

    I believe that if conses/gc were really cheap,
    there would be much less benefit to m-v-r.
    e.g. divide could just return (quotient . remainder), other objects could
    be cons'd up  (or put in vectors ...)

You certainly provided a fine argument for having multiple values here.  Compare
the last sentence in your first paragraph.  If divide returns two values, and you
only want one, you don't have to extract the first item in a multiple value, you
simply accept the first value and ignore the rest.  But if divide returns a cons
of the quotient and the remainder, and you only want the quotient you do have to
pay the overhead of extracting the quotient from that cons.  Not only is there
run-time overhead, there is conceptual overhead since now the packaging of the
multiple values is visible to the user.

Of course divide isn't a good example, because it surely open-codes and hence
generates different code depending on the number of values you ask for.

    The constant overhead looking
    for m-v-r in, for example, macsyma, which does not, at the moment, 
    use m-v-r even once, would be distasteful. 

The constant overhead is zero in any reasonable implementation of multiple
values.

∂14-Nov-82  0927	Martin.Griss <Griss at UTAH-20> 	Re: multiple-value return  
Date: 14 Nov 1982 1025-MST
From: Martin.Griss <Griss at UTAH-20>
Subject: Re: multiple-value return
To: Kim.fateman at UCB-C70
cc: Griss at UTAH-20, common-lisp at SU-AI
In-Reply-To: Your message of 13-Nov-82 2233-MST

I agree totally with Fateman; it seems these features are always added to support
some <1% code (if at all), that result in  alot of compiler hair just to
make the cost tolerable
-------

∂14-Nov-82  1012	Kim.fateman@Berkeley 	Re:  multiple-value return  
Date: 14-Nov-82 09:42:03-PST (Sun)
From: Kim.fateman@Berkeley
Subject: Re:  multiple-value return
Message-Id: <8210141741.18720@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A18697; 14-Nov-82 09:41:16-PST (Sun)
To: Moon@SCRC-TENEX@MIT-MC
Cc: common-lisp@su-ai

	
	The constant overhead is zero in any reasonable implementation of multiple
	values.
We seem to have different ground rules here.

Unless you remove all m-v stuff at compile time, I do not see how you can
write a Lisp that has m-v, which is as fast as a good one without m-v.
Since one can demonstrate the impossibility of total run-time removal,
Lisps with m-v will be slower.  And I believe this is whether or not
m-v are used.

If you are arguing that CL, or any "reasonable implementation" of lisp
already pays the run-time cost, that is a different argument.
(E.g. it has been argued that spaghetti stacks are free in interlisp
  because the cost has already been paid when implementing other features;
  yet overall, interlisp speed suffers somewhat for this generality.)

In summary:

In Franz and probably other VAX Lisps,
compiled access to a value on a stack is implemented
as an addressing mode: PART of a SINGLE INSTRUCTION!  If you can show how
to check for multiple-valued-ness without the execution of a single
instruction or the use of any data space, in a language not otherwise
encumbered, I will believe it is free.  If it is not free, I suggest
alternatives and justification be considered.

Note, I am not arguing against conceptual simplicity; in fact I
brought up the divide function to make that point.  If it is decided
that conceptual simplicity is worth doubling the time to access
values some percent of the time, fine.

∂14-Nov-82  1314	UCBERNIE.jkf@Berkeley (John Foderaro) 	m-v on conventional machines   
Date: 14-Nov-82 11:54:06-PST (Sun)
From: UCBERNIE.jkf@Berkeley (John Foderaro)
Subject: m-v on conventional machines
Message-Id: <8210141954.22028@UCBERNIE.BERKELEY.ARPA>
Received: by UCBERNIE.BERKELEY.ARPA (3.227 [10/22/82])
	id A22021; 14-Nov-82 11:54:14-PST (Sun)
Received: from UCBERNIE.BERKELEY.ARPA by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A00135; 14-Nov-82 12:55:05-PST (Sun)
To: common-lisp@su-ai

  I too must disagree with Moon's statement that m-v's are free on
conventional machines if the user doesn't use them:

1) You must put a special mark on the stack for every tail recursive
   call, whether you plan to use m-v's or not.  This is not free on
   conventional machines, and tail recursive calls happen often.

2) Lisps on conventional machines often have a mode which permits rapid
   execution at the price of losing the ability to interpret the stack's
   contents.  Since a m-v return requires being able to go back on the
   stack to find a possible m-v-b, such rapid execution modes would
   have to be forbidden, causing grief to those users who don't care
   about m-v's.   The difficulty of interpreting the stack's contents
   on conventional machines is compounded by the fact that the operating
   system often dumps data on the stack (during interrupts for example) and
   your lisp system will have to make sure that it ignores those stack
   frames.  Also, if you run multiple languages inside your lisp, then
   you will have stack frames whose form you have no way of predicting in
   advance.


As an exercise in futility, I will express my feelings on what m-v's should
do:
  m-v's should be a protocol for passing multiple values from callee to
caller.   If the caller does a m-v call and the last thing executed before
returning to the caller does a values, then the values will be transfered
back.  All other cases are undefined!!!!!   Like everything else in lisp, if
the user does something illegal it is his own fault and the system may or
may not catch it (depending on how expensive the checks are on a given
machine).  In a lisp on a conventional machine, the best place to check for
things like this

(multiple-value-list (progn (values 'a 'b 'c) nil)) --> (nil b c)

is not at runtime, but at compile time (or by using a special program which
does extensive type analysis of the source code).  Thus, since the above
example is illegal, its result is undefined, and so (nil b c) is as good a
value as any to return.



∂14-Nov-82  1350	Scott E. Fahlman <Fahlman at Cmu-20c> 	Multiple Values 
Date: Sunday, 14 November 1982  16:48-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   common-lisp at SU-AI
Subject: Multiple Values


All of these arguments about multiple values are interesting, possibly
valid, and should be kept in mind the next time we design a new Lisp
system.  It is too late for us to seriously consider any changes in the
fundamental function-calling mechanisms of Common Lisp unless it is
shown that the current mechanisms are fatally flawed -- not just
inelegant or slightly inefficient on some architectures.

-- Scott

∂14-Nov-82  1535	HEDRICK at RUTGERS 	results of analyzing answers to my question about m.v.'s    
Date: 14 Nov 1982 1827-EST
From: HEDRICK at RUTGERS
To: common-lisp at SU-AI
Subject: results of analyzing answers to my question about m.v.'s
Message-ID: <"MS10(2117)+GLXLIB1(1135)" 11871971621.32.19.89560 at RUTGERS>

Having started this discussion on multiple values, I feel some
responsibility to prevent it from going off into unnecessary directions.
What I was trying to do was to determine what was needed to implement
m.v.'s.  Moon's response, as well as a private interchange with Steele,
gave the information I needed.  Since other people seem to share my
original concerns, it seems worthwhile telling everybody the design I
have arrived at from this information. To be honest, I would prefer to
see a definition wherein an m.v. producer is an error unless there was
some m.v. receiver there to receive it. That is easy to implement.  But
I am now convinced that there are designs for implementing the existing
C.L. semantics without incurring unreasonable overheads on conventional
machines.

Let me approach this by successive approximation.

Stage I.  M.v. producer is called only when there is an m.v. receiver
to receive the value.

The Maclisp implementation will work here.  (VALUES A B C) simply saves
away the values of A, B, and C in some global places.  MV-LIST (or
anything else) just takes values from that global places and returns
them.  In most cases this mechanism would suffice taken alone. However
there are a couple of cases (MVPROG1 and MVCALL) where  multiple values
have to be saved while an arbitrary computation is done.  Thus it is
probably best for the values to be stored on a stack.  This will allow
for the possibility that m.v.'s can be done recursively.  The simplest
implementation is to push the number of m.v.'s on the top of the stack.
As long as every m.v. producer has an m.v. consumer, this implementation
should be sound.

Stage II.  The real case.

The problem is that the receiver may not call the producer directly.
Furthermore, we have no way of getting rid of m.v.'s if they are
produced erroneously, e.g.
   (multiple-value-list (values a b c) nil)
Thus I propose the following:

  - VALUES and VALUES-LIST will produce multiple values only if they
	know they are going to be used
  - we establish a protocol that allows us to follow the stack to
	see whether they are going to be used

The trickiest part is the second.  This is going to require some care
in the translator, but I claim that it is not that complex.  We have
three categories of calls:

  - calls where multiple values are required.  These are calls
	made by MV-LIST, MV-BIND, etc. (the m.v. consumers).  If the
	thing called would not normally produce m.v.'s, we need to
	convert the single normal value to a single m.v.
  - calls where multiple values are not allowed.  There are calls
	such as all but the last in a PROGN, where any m.v.'s are
	discarded.
  - calls where m.v.'s are returned if available, but are not required.
	I have it on good authority that the only case where this applies
	is terminal calls, i.e. the last call in a function (last being
	judged in execution, not lexically.  e.g. in
		(defun foo nil (cond (x (bar)) (t (baz]
	(bar) is a terminal call.

Let's ignore the third case for the moment.  All we need is some way to
mark calls so VALUES can tell whether m.v.'s are really going to be
used.  Clearly we want to mark the calls where m.v.'s are going to be
used, as opposed to those where m.v.'s are not going to be used, since
we want the overhead to be confined to users of m.v.'s. On the PDP-10
the obvious way to do this is to put a special instruction after the
call.  One way to do this is to put a particular no-op after each such
call. (Since the PDP-10 has several million kinds of no-ops, we can
afford to use one as a flag.)  Then VALUES would simply look up the
stack and see if its return address points to such a no-op.  As it
happens, we will probably do something a bit trickier.  We will probably
use a call to a routine MAKE-MV.  Thus a call done inside MV-LIST would
look like
  (MULTIPLE-VALUE-LIST (FOO) (BAR))
	CALL FOO	;m.v.'s not needed - nothing special
	CALL BAR	;m.v.'s needed - flag it with CALL MAKE-MV
	CALL MAKE-MV
	CALL MULTIPLE-VALUE-LIST ;do the actual return of the m.v.'s

The idea is that when we return from BAR, we will do a skip return if
we are actually returning multiple values (I will show how that happens
in a minute).  In that case the m.v.'s are left as is.  If we are not
returning m.v's, we do the normal return, and fall into the call to
MAKE-MV.  MAKE-MV is the routine that takes the conventional single
value and stores it away as a single multiple value.  Clearly this is
going to have to be done anyway when m.v.'s are needed, so we might as
well use CALL MAKE-MV as the flag that m.v.'s are required.

Now, we have two ways of implementing this, either of which is fairly
easy:

1) make sure that all terminal calls are compiled as jumps.  This is
a fairly standard optimization.  If done reliably, it guarantees that
the third case I ignored above will never occur.  VALUES will simply
be able to look at the place where it called directly, with no fancy
stack chasing.  If the return address points to CALL MAKE-MV,
VALUES puts the m.v.'s onto the mv stack, and takes the skip return.
Otherwise it returns the first of the m.v.'s, ignores the rest, and
does a conventional return.  If you choose this implementation, then
you will have to look at forms such as MVPROG1, which explicitly pass on
m.v.'s in contexts other than terminal calls.  They will have to
do calls that require m.v.'s, save those m.v.'s, and then themselves
return as VALUES (or any other m.v. producer) would do (i.e. looking
at their return address and throwing away the m.v.'s if they are not
required).

2. Have VALUES detect terminal calls, and simply follow the stack up
until something is found which is not a terminal call.  Otherwise
do things as in 1.  (That is, once you find something other than a
terminal call, look to see whether the return address there points to
MAKE-MV...)  If you choose this implementation there is a simple
modification for handling MVPROG1 and similar forms.  Add yet another
special mark (i.e. a no-op used only for this), call it MVFLAG.

   (mvprog1 (foo) (bar))
	call foo
	mvflag
	push returned value
	call bar
	pop returned value
	return

If somewhere inside FOO there is a call to VALUES, the stack search
will detect MVFLAG as the next instruction after the return address.
MVFLAG will be treated like a terminal call, i.e. the stack search
will continue to see whether the caller of the MVPROG1 really needed
the m.v.'s or not.  If so, they will be put on the m.v. stack, and
then the caller will retrieve them.  (The call to BAR will not be
pass on m.v.'s because of the POP after it.  This POP prevents the
next thing from being a RETURN, and thus prevents it from looking
like a terminal call.)

This mechanism has the advantage that if my informants are wrong, and
there is some context other than terminal calls that preserves m.v.'s,
we can handle it by putting MVFLAG there.

Both of the mechanisms suggested have only slight overhead, and that
overhead exists only if m.v.'s are used.  The extra no-op's are used
only in code compiled for m.v. receivers (or constructions such as
MVPROG1 that explicitly protect m.v.'s).  The m.v. producers need
only look up the stack to see what to do.  m.v.'s are never produced
if they are going to be thrown away.  I think that these mechanisms,
or something closely related, should work on machines other than the 
PDP-10.

I am not pleased with this sort of hackery, but it is no worse than
that needed to implement default arguments, &REST, and funarg's.
I would rather see Lisp free from this sort of thing, but I think I
have shown that it is possible to do with acceptable overhead and
no increased complexity in the compiler (except that you must be
able to detect terminal calls, something that all compilers known to
me do anyway).


None the less, I do not accept the argument that it is too late to
eliminate M.V.'s from Common Lisp, should people decide to do so.
Clearly the time to eliminate things is now.  We will be able to add
things later, but not to remove them.  But you should realize that
I am really a reactionary.  If it came to a vote, I would vote against
default arguments, &REST, and multiple values.
   --------

∂14-Nov-82  2207	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	implementing multiple values
Date: 13 Nov 1982 2117-EST
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: implementing multiple values
To: common-lisp at SU-AI

We have gotten to the place where I have to actually implement multiple
values.  I find that I need to know a bit more about what the semantics
are, and what compromises are and are not acceptable.  What I would love
to hear is that I can use the Maclisp implementation.  It is certainly
the obvious approach for a conventional machine:  VALUES just saves away
its arguments in some global place (global variables - probably we would
use a separate stack - it doesn't much matter).  Then MULTIPLE-VALUE-xxx
simply retrieves them and makes them into a list, binds variables to
them, etc.  The problem turns out to be knowing when it is safe to use
those stored-away values. E.g. consider the following example from Maclisp:

(multiple-value-list (progn (values 'a 'b 'c) nil)) --> (nil b c)

It seems fairly clear that this should return either (nil) or (a b c).
This seems like a simple bug in the Maclisp implementation.  But it
does illustrate the kind of problems that are going to come up.
I do need to know exactly how long multiple values last.  Here are
the definitions I can see as being reasonable, with the ones I
prefer first (as you might guess, this is simply in order of how easy
they are to implement):

  - an m.v. receiver is only valid when the most recent value computed
	was computed by an m.v. producer.  Other cases are errors, and
	the results are undefined.
  - an m.v. receiver returns the most recent values produced by an
	m.v. producer.  Other non-multiple-values produced in the
	interim are ignored.
  - an m.v. receiver returns the most recent value computed, m.v. or
	otherwise.
  - like the last, except that some constructs "kill" multiple values
	and some do not.  If this definition is used, we need a list
	of the ones that do and don't.

Probably the last two definitions are going to require that every
value computation will interact with the m.v. mechanism, an overhead
I would like to avoid.  At least this is true if m.v.'s can be survive
function returns.  Consider the following example:

    (defun foo nil (bar) 'success)

Since (BAR) may return multiple values, even something as simple as
'SUCCESS is going to have to explicitly do something to make sure that
any multiple values returned by BAR are no longer active.  Either that
or

   (defun foo nil (bar))

is going to have to do something explicit to make sure that if (BAR)
happens to return multiple values, they get returned.

In any case, I need a precise definition.  Can somebody help? The
following cases are given just to spark your thoughts, not to relieve
Guy of the need to give a  precise specification. Please assume that
functions stay defined until they are explicitly redefined.

1.

(defun foo nil (values a b c))
(defun bar nil (foo))
(defun baz nil (multiple-value-list (bar]

2.

(defun baz nil (multiple-value-list
		 (cond ((moon-phase) (foo))
		       (t  (trunc 5 2]

3.

(defun bar nil (cond ((moon-phase) (foo))
		     (t (trunc 5 2]
(defun baz nil (multiple-value-list (bar]

4.

(defun baz nil (multiple-value-list (progn (foo]

5.

(defun baz nil (multiple-value-list (progn (foo) nil]



-------

∂16-Nov-82  0848	Kent M. Pitman <KMP at MIT-MC> 	Multiple Value Return and Continuation Passing Style 
Date: 15 November 1982 06:34-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  Multiple Value Return and Continuation Passing Style
To: common-lisp at SU-AI

I guess it's worth noting just for completeness that there is an alternative
to the multiple-value-return idea which is suggested by continuation-passing
style a la Sussman/Steele papers... I take no stand on whether this would be
the right thing for Common-Lisp, but I point it out for completeness since
it involves no pervasive effect upon the whole interpreter to implement things
in this style. Here's an example from the preliminary T manual (May '82):

    (DIV2 n1 n2 proc)

     Division yielding quotient and remainder. Not yet implemented. The
     PROC should be a procedure of two arguments; it will be invoked on
     the quotient and remainder. For example:

      (DIV2 11 4 LIST)  => (2 3)
      (DIV2 11 4 PROJ0) => 2

Where PROJ0 is like the subr version of BLOCK0 (which is T's name for PROG1).

This is upward compatible with the LispM in that although it doesn't use 
multiple values at all, it can be implemented by taking advantage of 
functions that return them. eg, a sample LispM implementation would be:

 (DEFUN DIV2 (X Y FN)
   (MULTIPLE-VALUE-BIND (QUO REM)
       (QUOTIENT X Y)
     (FN QUO REM)))

Also, remember that constructs like:

 (MULTIPLE-VALUE-LIST (PROG1 (G) (H) (I)))

where (G) might return multiple values can always be re-written if G can
be made to accept a continuation arg as something like:

 (G #'(LAMBDA (&REST ARGS) (H) (I) ARGS))

The intent here is not to say this is what we should do, but just to make
sure we're not overly restricting our mode of thinking in this issue...
-kmp

∂16-Nov-82  0856	Kim.fateman@Berkeley 	multiple thanks   
Date: 15-Nov-82 08:53:20-PST (Mon)
From: Kim.fateman@Berkeley
Subject: multiple thanks
Message-Id: <8210151653.22738@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A22720; 15-Nov-82 08:53:18-PST (Mon)
To: hedrick@rutgers
Cc: common-lisp@su-ai

Thanks for presenting a proposed mechanism for multiple values which seems
to penalize the producers of multiple values (and the implementors of 
lisp systems).  Yet,now there is this hidden cost in
using some m-v producers: should one use them, since in some
circumstances they have to do a fair amount of stack-grovelling?
(e.g. one might think that "floor" would always be fairly cheap to use).

∂16-Nov-82  0859	Masinter at PARC-MAXC 	Named lambdas    
Date: 15-Nov-82 11:22:23 PST (Monday)
From: Masinter at PARC-MAXC
Subject: Named lambdas
To: common-lisp at SU-AI

That the interpreter/compiled code forgets the name of the function you are executing in and/or the debugger has trouble finding it from looking at
the stack seems more like a lack of functionality on the part of the debugger.
Enough information is there to determine it (e.g., looking at the instruction 
preceding the return PC to see what function was called) that a kludge like
NAMED-LAMBDA doesn't seem at all a reasonable part of the white pages.

I had imagined, incorrectly, that NAMED-LAMBDA actually had some semantics
associated with it, e.g. it was similar to the Interlisp notion of creating
a frame with a name which was visible to STKPOS, RETFROM, and other stack
primitives. The current common-lisp spec seems to have a big hole in the area
of primitives which would allow one to write an implementation-independent 
debugger.

∂16-Nov-82  0900	JONL at PARC-MAXC 	Multiple-Value implementations 
Date: 15 NOV 1982 1421-PST
From: JONL at PARC-MAXC
Subject: Multiple-Value implementations
To:   hedrick at RUTGERS
cc:   common-lisp at SU-AI, jonl

Apologies for not being able to reply as fast and prolifically
as others on this issue (still "snowed under" from house buying etc),
but I think the VAX/NIL method of handling multiple values should
be considered.  It has the virtue of being incredibly more
siimple than the summary you suggested, and the minor disadvantage
that MVPROG1 is slightly more expensive than it would be in a stack-
oriented implementation.

One machine register is dedicated to communicating back the number
of values returned by any function.  This is the only failing of the
MacLisp "add-on" macro scheme -- it was judged to be too expensive  to
the non MV user to have every function, including built-in system
functions, take the time (adn space!) to do this; besides, all compiled
code would be invalidated should such a demand be enforced.  

But back to the to the topic: on the VAX, the function-exit sequence includes
a two-byte instruction to set the number of values being returned.  Thus
(COND ((FOO) 'A) (T (VALUES 'B 'A)))  would have two slightly different exit
sequences (if this form were the return-value of a function).  All values
are returned in a "value-return" vector; and as Moon rightly pointed out,
having the first location of this conceptual vector be the register where
single-value function results would *normally* be found means that non-users
of the MV stuff pay only the two-byte penalty (this is truly zilch on the VAX,
considering its funciton call overhead, and it ought to be so on the PDP10).
Since this is not a stack protocol, then a tail-recursive instance of MVPROG1 must
be compiled in such a way as to save-and-restore the active value-return vector;
the cost of this may not be zilch (that is, it may actually be measurable), but
then how often and how important is this case?

The compiler need not be more clever than to "fold-out" lexical instances of
apparent mv usage.  Callers who want exactly one value from a function call need
not be perturbed at all (unless  you want to provide run-time checking for the
case of zero arguments returned).  Sume support might be given to the interpreter so 
that it not actually cons-up-into-a-list the multiple values returned -- such
as using resource-allocated scratch vectors or whatnot; perhaps some syntax is
needed whereby a "scratch list" can be given to MULTIPLE-VALUE-LIST.  [Unfortunately,
not all of these ideas got integrated into VAX/NIL before the mail development
group dissolved -- it was just using the MacLisp-like macros last time I checked --
but most of them had been coded and tested out.  It  may still be at what
you called "stage 1".]

I prefer the notion of disconnecting any rigid link between caller and callee
on this mater -- there is no m ore reason why returning multiple-values when not
explicitly "called for" is bad than there is reason to proscribe value-returning
functions from being called "for effects".  Like Moon pointed out in reply to
Fateman's concern: it's better to produce the multiple valuues even when not
wanted than it would be to produce some gross structure that had to be "torn apart"
at run time to get at the one value wanted.

∂16-Nov-82  0900	Masinter at PARC-MAXC 	Re: #, 
Date: 15-Nov-82 11:48:48 PST (Monday)
From: Masinter at PARC-MAXC
Subject: Re: #,
To: common-lisp at SU-AI

I would like to see most of the special forms currently in reader macros
merely be abbreviations for some form, since then it would not preclude
building a residential environment around common-lisp.

As for #,: Interlisp has three macros for constants:

(CONSTANT form). Returns the value of form available at compile time. 

(LOADTIMECONSTANT form). Returns the value of form as of load time.

(DEFERREDCONSTANT form). Returns the value of form as of first execution.

All of these merely return the value of "form" when interpreted. Some 
implementations of Interlisp don't support LOADTIMECONSTANT (the compiled-
code loader won't handle it) and those get turned into DEFERREDCONSTANT.

Larry

∂16-Nov-82  0957	DLW at MIT-MC 	multiple-value return    
Date: Monday, 15 November 1982  19:34-EST
Sender: DLW at MIT-OZ
From: DLW at MIT-MC
To:   Kim.fateman at Berkeley
Cc:   common-lisp at su-ai
Subject:  multiple-value return
In-reply-to: The message of 14-Nov-82 09:42:03-PST (Sun) from Kim.fateman@Berkeley

If you spent more time thinking about how to produce a low-cost
implementation and less time trying to convince us to remove multiple
values from the language, I bet you could come up with
a cheap implementation.  It's largely a matter of how
you choose to expend your efforts.  I'm glad there are
some people on this mailing list who are spending their
time trying to solve problems and figure out good ways
to implement Common Lisp.

Indeed, a very tricky and crafty scheme might be needed
to implement multiple values efficiently.  That's fine.
As long as the user doesn't see it, it's worth it.  I
consider this analogous to the "fast number" scheme in
PDP-10 Maclisp.  Our goal should be to eliminate the
"Lisp is inherently inefficient and can't ever be competitive
with other languages" mentality.

It's also a good thing that Common Lisp is not being designed
purely by a group of language implementors, who have lots
of motivation to eliminate features to keep their own job
easy.  Common Lisp's design has been heavily influenced
by the experience of real users of Maclisp and the Lisp Machine,
who are interested in getting work done and writing code that
can be both efficient and elegant, and who are not interested
especially in keeping things easy for the implementors.  Let
us continue to develop Common Lisp with the needs of the user
foremost in our minds.

∂16-Nov-82  1028	BROOKS at MIT-OZ at MIT-MC 	Re: DLW's message and Fateman's FLOOR.    
Date: 16 Nov 1982 1316-EST
From: BROOKS at MIT-OZ at MIT-MC
Subject: Re: DLW's message and Fateman's FLOOR.
To: common-lisp at SU-AI

Right.

Most of the time the complaint about FLOOR being expensive
doesn't apply, as it will get compiled down to one result.
But what about when it is a tail recursive call. The compiler
can't know whether both values are needed. How about having
some way of declaring that a function will only return one
value: e.g.

(DEFUN USER-MOD3 (X)
  (DECLARE (SINGLE-VALUE USER-MOD3))
  (MOD X 3))

where we probably want something less ugly.

I suspect (as long as we don't arbitrarily start loading up all
sorts of random functions with multiple values) that this would
only be needed very infrequently.
-------

∂16-Nov-82  1052	Scott E. Fahlman <Fahlman at Cmu-20c> 	DLW's message and Fateman's FLOOR.  
Date: Tuesday, 16 November 1982  13:52-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   BROOKS at MIT-OZ at MIT-MC
Cc:   common-lisp at SU-AI
Subject: DLW's message and Fateman's FLOOR.


I don't think we need a new declaration.  If you want to suppress the
return of multiple values for some form in tail-recursive position, you
can easily do that with, for example,

... (return (prog1 (trunc x y))) ...

Static analysis at compile time will now show that only one value is
coming back.  As Rod Brooks points out, one would seldom bother with
this: it is useful only in a call to a multiple-value producer in
tail-recursive position in a place where the speed matters.  The use of
TRUNC and friends in a context where the consumer of the value is
lexically apparent can be optimized at compile-time.

-- Scott

∂16-Nov-82  1106	HEDRICK at RUTGERS 	Re: #,    
Date: 16 Nov 1982 1355-EST
From: HEDRICK at RUTGERS
To: Masinter at PARC-MAXC, common-lisp at SU-AI
Subject: Re: #,
Message-ID: <"MS10(2117)+GLXLIB1(1135)" 11872446256.46.19.20844 at RUTGERS>
Regarding: Message from Masinter at PARC-MAXC of 15-Nov-82 1148-EST

I strongly concur with Masinter's request to define the forms to which
the # constructs expand.  It should be possible to represent anything
that can be in a Lisp file using S-expressions, for fairly obvious
reasons.  Although I regard existing "residential system" as
relatively unattractive (in particular I think most of our users
prefer an LEDIT interface to EMACS to the Interlisp structure editor),
we have some very attractive proposals for systems that mix features
of in-core function editors and systems such as LEDIT.  Certainly this
kind of system will only work if we can write back out what we read
in.  This includes both # constructs and comments.  We will surely
define these things locally if we have to, but it seems like a good
idea for everybody to agree on them.
   --------

∂16-Nov-82  1117	Scott E. Fahlman <Fahlman at Cmu-20c> 	DLW's message and Fateman's FLOOR.  
Date: Tuesday, 16 November 1982  13:52-EST
From: Scott E. Fahlman <Fahlman at Cmu-20c>
To:   BROOKS at MIT-OZ at MIT-MC
Cc:   common-lisp at SU-AI
Subject: DLW's message and Fateman's FLOOR.


I don't think we need a new declaration.  If you want to suppress the
return of multiple values for some form in tail-recursive position, you
can easily do that with, for example,

... (return (prog1 (trunc x y))) ...

Static analysis at compile time will now show that only one value is
coming back.  As Rod Brooks points out, one would seldom bother with
this: it is useful only in a call to a multiple-value producer in
tail-recursive position in a place where the speed matters.  The use of
TRUNC and friends in a context where the consumer of the value is
lexically apparent can be optimized at compile-time.

-- Scott

∂16-Nov-82  1151	Guy.Steele at CMU-CS-A 	1000th message  
Date: 16 November 1982 1315-EST (Tuesday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: 1000th message

Since I started collecting COMMON-LISP messages into a
separtate file on 27 October 1981, this is the one-thousandth
message.

∂16-Nov-82  1227	MOON at SCRC-TENEX 	Defining the forms to which the # constructs expand    
Date: Tuesday, 16 November 1982  15:22-EST
From: MOON at SCRC-TENEX
To:   HEDRICK at RUTGERS, Masinter at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Defining the forms to which the # constructs expand

I agree with you, since I think that primitives should always be available
to the user.

Note, however, that you both missed a vital point.  Neither #. nor #,
expands into a form!  Both of these can be used inside of an expression
which is data, as well as inside an expression which is a program.  When
reading into the environment (as opposed to reading into the compiler),
the #. and #, constructs must produce precisely the result of evaluating
their argument.  They cannot produce any sort of "wrapper" around it.

The only hidden primitive involved in #. and #, is the "magic wrapper"
that #, uses when reading into the compiler.

The inability to deal with things like #. is the inherent bankruptcy of
residential systems, if by that you mean an editor which regenerates your
source text from the actual contents of memory, rather than keeping a
separate copy of it.  On the other hand, if by residential system you mean
merely the ability to switch rapidly between typing at the Lisp evaluator
and typing at the editor, and the ability to edit single functions and get
them into memory without the overhead of reading or compiling whole files,
this is what we have in the Lisp machine, while still using text-based
editing, and Boy!  Is it ever an improvement over the old file-based ways
of doing things!

∂16-Nov-82  1247	BROOKS at MIT-OZ at MIT-MC 	(prog1 (trunc x y))   
Date: 16 Nov 1982 1524-EST
From: BROOKS at MIT-OZ at MIT-MC
Subject: (prog1 (trunc x y))
To: common-lisp at SU-AI

(return (prog1 (trunc x y))) looks like awful black magic, and
the intent is not very clear. How about
  (or (trunc x y) ())
since in that position multiple values are defined not to work
so the compiler can figure it out there too. I'd prefer to
see a clear mechanism provided rather than (by default) encouraging
users to come up with obscure gobble-de-gook to make use of
essentially side effects of the semantics of special forms.
-------

∂16-Nov-82  1334	Alan Bawden <ALAN at MIT-MC> 	(prog1 (trunc x y)) 
Date: 16 November 1982 15:45-EST
From: Alan Bawden <ALAN at MIT-MC>
Subject:  (prog1 (trunc x y))
To: common-lisp at SU-AI

I believe the LispMachine uses (VALUES (TRUNC X Y)) to force the return of
a single value.  What could be clearer?

∂16-Nov-82  1333	Guy.Steele at CMU-CS-A 	Forcing one value from a function   
Date: 16 November 1982 1538-EST (Tuesday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: Forcing one value from a function

I have been given to believe that in Lisp Machine LISP
the approved convention is
	(VALUES (FLOOR x y))
to get back exactly one value.  I suppose this might be
somewhat misleading to the novice.
--Guy

∂16-Nov-82  1423	Ron <FISCHER at RUTGERS> 	Re: Obliquity of the vernacular...
Date: 16 Nov 1982 1648-EST
From: Ron <FISCHER at RUTGERS>
Subject: Re: Obliquity of the vernacular...
To: BROOKS at MIT-OZ at MIT-MC, common-lisp at SU-AI
In-Reply-To: Your message of 16-Nov-82 1524-EST

I agree with BROOKS.  Where is all the perspicuity to which the manual
constantly refers?  How could something as obscure as (prog1 (trunc x
y)) be suggested in this light?  Give the poor thing a name if it will
be used.

(ron fischer)
-------

∂16-Nov-82  1555	Guy.Steele at CMU-CS-A 	Forcing one value from a function   
Date: 16 November 1982 1538-EST (Tuesday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: Forcing one value from a function

I have been given to believe that in Lisp Machine LISP
the approved convention is
	(VALUES (FLOOR x y))
to get back exactly one value.  I suppose this might be
somewhat misleading to the novice.
--Guy

∂16-Nov-82  1805	Eric Benson <BENSON at UTAH-20> 	Re: (prog1 (trunc x y))    
Date: 16 Nov 1982 1650-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: (prog1 (trunc x y))
To: BROOKS at MIT-OZ at MIT-MC, common-lisp at SU-AI
In-Reply-To: Your message of 16-Nov-82 1324-MST

Indeed, this seems like a natural candidate for a declaration, being in the
category of "optional optimization." (DECLARE (SINGLE-VALUE TRUNC)) isn't
that ugly.
-------

∂16-Nov-82  1806	Masinter at PARC-MAXC 	Re: Defining the forms to which the # constructs expand  
Date: 16-Nov-82 16:25:04 PST (Tuesday)
From: Masinter at PARC-MAXC
Subject: Re: Defining the forms to which the # constructs expand
In-reply-to: MOON's message of Tuesday, 16 November 1982  15:22-EST
To: (MOON at SCRC-TENEX)
cc: common-lisp at SU-AI

Foo. By a residential system, I mean one in which you can write programs in Lisp to
write and modify programs (using the normal S-expression representation of the
program), and have the program-modified programs be first class.

I suppose since you haven't seen the point of this, I should give an example.
Let's suppose, for example, that I wanted to swap the order of arguments to a
function. I might write a program/edit command which would go through my code,
switching the  arguments, and wrapping the whole thing with a LET if necessary
to enforce argument evaluation. 

I could imagine writing TECO macros to do this, where you look at the text and
pretend that you were looking at the s-expression, but the most natural way to
do this is to READ in the program, apply a transformation, and prettyprint it
out again. It isn't acceptable if information like #. and #, get lost. It is
preferable that the mechanism by which that information is preserved is visible,
so that the code walkers can know about it.

You may not think this is an important kind of thing to do, but it seems that
defining COMMON-LISP in a way which precludes building such tools is unnecessary
and a mistake.

∂16-Nov-82  1817	Eric Benson <BENSON at UTAH-20> 	Re: (prog1 (trunc x y))    
Date: 16 Nov 1982 1650-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: (prog1 (trunc x y))
To: BROOKS at MIT-OZ at MIT-MC, common-lisp at SU-AI
In-Reply-To: Your message of 16-Nov-82 1324-MST

Indeed, this seems like a natural candidate for a declaration, being in the
category of "optional optimization." (DECLARE (SINGLE-VALUE TRUNC)) isn't
that ugly.
-------

∂16-Nov-82  1817	Masinter at PARC-MAXC 	Re: Defining the forms to which the # constructs expand  
Date: 16-Nov-82 16:25:04 PST (Tuesday)
From: Masinter at PARC-MAXC
Subject: Re: Defining the forms to which the # constructs expand
In-reply-to: MOON's message of Tuesday, 16 November 1982  15:22-EST
To: (MOON at SCRC-TENEX)
cc: common-lisp at SU-AI

Foo. By a residential system, I mean one in which you can write programs in Lisp to
write and modify programs (using the normal S-expression representation of the
program), and have the program-modified programs be first class.

I suppose since you haven't seen the point of this, I should give an example.
Let's suppose, for example, that I wanted to swap the order of arguments to a
function. I might write a program/edit command which would go through my code,
switching the  arguments, and wrapping the whole thing with a LET if necessary
to enforce argument evaluation. 

I could imagine writing TECO macros to do this, where you look at the text and
pretend that you were looking at the s-expression, but the most natural way to
do this is to READ in the program, apply a transformation, and prettyprint it
out again. It isn't acceptable if information like #. and #, get lost. It is
preferable that the mechanism by which that information is preserved is visible,
so that the code walkers can know about it.

You may not think this is an important kind of thing to do, but it seems that
defining COMMON-LISP in a way which precludes building such tools is unnecessary
and a mistake.

∂16-Nov-82  1817	Glenn S. Burke <GSB at MIT-ML> 	Re: #,  
Date: 16 November 1982 19:24-EST
From: Glenn S. Burke <GSB at MIT-ML>
Subject: Re: #,
To: common-lisp at SU-AI

What can be done to allow load-time evaluation in a general fashion is
this.  (This has been implemented in Maclisp.  I won't say how because
it is a dirty kludge and was then specialized to a particular purpose.)

Provide the user with some means by which he can get load-time evaluation
performed to provide some object, no matter where it is in whatever
structure is being "dumped", by virtue of having some symbol (of HIS
choosing) as the car of a list.  (The CADR being the form which gets
evaluated at load time, for instance, although you might not want to
maintain that restriction.)

Then, the user is free to provide how to handle:
   (1)  What to do when the form is encountered by the compiler as a
form to be compiled, by defining some sort of compiler-macro or
optimizer or rewrite rule or whatever we have for that (which we
should also define).
   (2)  What to do when the form is encountered by the evaluator.
Since these forms are typically produced during compilation (by virtue
of the reading being done by the compiler, something which the user
should be able to determine [yet another thing to define]), this could
be considered an error, or the function could be a macro which quotes
itself, effectively causing the object to be self-evaluating.

So, for example, if this worked by virtue of the symbol having a
non-null :load-time-evaluation-form property, one might implement the
Maclisp SQUID form as follows:

;SQUID, "Self Quoting Internal Datum", has as its value a marker which
; you list around a form which should be evaluated at load time.  THe
; form is otherwise treated as being self-evaluating.
(defvar squid
  (copysymbol 'squid))

;Tell the compiler/assembler about the marker.
(putprop squid t :load-time-evaluation-form)

;Define how such a form compiles and evaluates:
(defun squid-quoter (form)
   (list 'quote form))

;I guess the following is probably wrong for common-lisp but anyway:
(fset squid '(macro . squid-quoter))

Then, the code for #, could simply do
	(if *reading-for-compilation*
	    (list squid (read))
	    (eval (read)))

"*reading-for-compilation*" should probably be
"*reading-for-external-compilation*" to distinguish it from the case
when the compiler is compiling directly to core.
----
Of course another way to do this is to have a flavor or
extend/message-passing system and simply define the right messages to
interface to the compiler and evaluator.
----
If you try to generalize this too much you run into problems
differentiating your runtime and compile-time environments;  for
example a macro which contains pointers to datastructure which should
be created with a special load-time-eval construct, but it can be used
both by the interpreter and the compiler.  Having the compiler not
bash the runtime environment with macro definitions it is compiling
(but save the definitions away and expand them otherwise) alleviates
this, but only for the single-file compilation.  There are potentially
other subtleties which make the read switch inadequate, such as having
a single textual definition which both needs to be compiled to a file
and stored in core (the traditional macro definition bashing the
runtime environment, for example, but this might arise in other ways).

Anyway, the reason i brought all this up is that we have played some
with writing, saving, and referring to nodes in semantic networks
here, and that is the sort of thing which "users" might try to do.
[JonL and/or Guy can testify to the Maclisp hacking in this regard
from variously the OWL, LMS, XLMS, and Brand-X systems, each of which
implemented yet another representation scheme and found the Lisp
primitives inadequate.]

∂16-Nov-82  1852	Guy.Steele at CMU-CS-A 	Masinter's remarks on #,  
Date: 16 November 1982 2129-EST (Tuesday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: Masinter's remarks on #,

I am very much in sympathy with the goal of writing program-writing programs
and program-transforming programs.  I don't think the existence or
non-existence of #, makes that job any harder or easier, however.
I think that any mechanism that can also preserve the distinction
between #o777 and 511, or for that matter between |(foo| and \(foo,
or even between (x . (a b c)) and (x a b c) [I sometimes write the former
in a constant a-list if necessary to preserve visual similarity of the
entries]---such a mechanism can also deal with #,.  The fact is that
vanilla READ is a many-to-one mapping; by the time you've got the
S-expression in memory you have already lost.  Preservation of the
information requires using a parser other than READ, which may imply
generation of internal structure different from what READ would
produce, that may be unsuitable for evaluation.  Alternatively, various
kinds of hashing could be used.  Nevertheless, in every LISP from
LISP 1.5 on, READ has been a many-to-one mapping.

∂16-Nov-82  2007	MOON at SCRC-TENEX 	Re: Defining the forms to which the # constructs expand
Date: Tuesday, 16 November 1982  23:02-EST
From: MOON at SCRC-TENEX
To:   Masinter at PARC-MAXC
Cc:   common-lisp at SU-AI
Subject: Re: Defining the forms to which the # constructs expand
In-reply-to: The message of 16-Nov-82 16:25:04 PST () from Masinter at PARC-MAXC

    Date: 16-Nov-82 16:25:04 PST (Tuesday)
    From: Masinter at PARC-MAXC

    You may not think this is an important kind of thing to do, but it seems that
    defining COMMON-LISP in a way which precludes building such tools is unnecessary
    and a mistake.

I could say exactly the same thing, word for word, about #,.  Of course the
presence of #, in the language hardly precludes building tools that can't work
with it, it only means that those tools cannot work with that construct, and a
user must choose one or the other.  This is not ideal, but I thought we went
through this discussion last year, and concluded that there was no way to
satisfy all requirements at the same time.  Of course, as Steele points out in
his message, you only have to crank up your cleverness a little and use a
smarter reader, and you can still write the same tools.

∂16-Nov-82  2113	Glenn S. Burke <GSB at MIT-ML> 	multiple values   
Date: 17 November 1982 00:12-EST
From: Glenn S. Burke <GSB at MIT-ML>
Subject: multiple values
To: common-lisp at SU-AI

NIL is not going to use the multiple-value scheme described by JonL,
but most likely something similar to what is in use on the "A"
lisp machine.  Function calls which pass back multiple-values
tail-recursively will be flagged;  extra information will be pushed
for call frames which expect to receive multiple values.  Returning
multiple values will involve tracing back call frames, and then if
it is found that multiple values are not expected, throwing them away,
otherwise interpreting what was pushed there in some fashion.

A declaration to the effect that a function returns exactly one value
always will be helpful.  My feeling is that this should not be used to
enforce the single-value return, except perhaps by having the
interpreter complain when the function returns multiple values.  (We
have some philosophy about declarations and program behaviour, don't
we?)  Actually stripping extra values can be done with (VALUES
<form>), which doesn't seem to me to be to be particularly unclear.

∂17-Nov-82  0305	Masinter at PARC-MAXC 	Re: #, 
Date: 15-Nov-82 11:48:48 PST (Monday)
From: Masinter at PARC-MAXC
Subject: Re: #,
To: common-lisp at SU-AI

I would like to see most of the special forms currently in reader macros
merely be abbreviations for some form, since then it would not preclude
building a residential environment around common-lisp.

As for #,: Interlisp has three macros for constants:

(CONSTANT form). Returns the value of form available at compile time. 

(LOADTIMECONSTANT form). Returns the value of form as of load time.

(DEFERREDCONSTANT form). Returns the value of form as of first execution.

All of these merely return the value of "form" when interpreted. Some 
implementations of Interlisp don't support LOADTIMECONSTANT (the compiled-
code loader won't handle it) and those get turned into DEFERREDCONSTANT.

Larry

∂17-Nov-82  0305	Alan Bawden <ALAN at MIT-MC> 	Defining the forms to which the # constructs expand    
Date: 16 November 1982 21:45-EST
From: Alan Bawden <ALAN at MIT-MC>
Subject:  Defining the forms to which the # constructs expand
To: Masinter at PARC-MAXC
cc: Moon at SCRC-TENEX, common-lisp at SU-AI

    Date: 16-Nov-82 16:25:04 PST (Tuesday)
    From: Masinter at PARC-MAXC

    ..., but the most natural way to do this is to READ in the program,
    apply a transformation, and prettyprint it out again. It isn't
    acceptable if information like #. and #, get lost. It is preferable
    that the mechanism by which that information is preserved is visible,
    so that the code walkers can know about it.

    You may not think this is an important kind of thing to do, but it seems
    that defining COMMON-LISP in a way which precludes building such tools is
    unnecessary and a mistake.

Common Lisp is already chocked full of reader features that cannot be
preserved across an operation such as you discribe.  Things like the case
of symbols and the base of numbers are all lost in this procedure.  The ";"
comment character is pretty hard to deal with through reading and printing
(you can't just expand into a form), and no scheme I have yet seen will
properly preserve all cases of "`"'ed expressions (although the MacLisp
scheme for this is pretty close).

I would NEVER run any of my MacLisp or LispMachine code through READ and
then PRINT, it would render it totally unreadable.  If precluding such
tools is a mistake, then we have made that mistake long ago.


∂17-Nov-82  1323	JONL at PARC-MAXC 	Expansion of #, and the "residential" question.    
Date: 17 NOV 1982 1322-PST
From: JONL at PARC-MAXC
Subject: Expansion of #, and the "residential" question.
To:   moon at MIT-AI, masinter, alan at MIT-MC
cc:   common-lisp at SU-AI

As one who has "crosssed the barrier" between the MacLisp/Interlisp
style of programming, let me proffer an opinion as to what the
"residential" style means.

"Residential" means that files, in the sense of structured
words/bytes on some disk volume, don't really exist!

At first I was taken aback when I found out that Interlisp's
FILEPKG only incidentally dealt with "files" in the above sense.
A "file" is primarily viewed as an agglomeration of functions,
variables with initial values, macros, typed-definitions and so on.
The problems observed to stem from the many-to-one mapping of
READ are irrelevant, and somewhat orthogonal to this issue; in fact,
Interlisp does have a #. feature in its reader -- control-Y -- and
although it doesn't have a general input-radix feature, you can
type numbers in octal or decimal and no attempt is made to remember
how it was read in.

Of course, real disks do exist, and the FILEPKG will incidentally 
"preserve" a "residential file" by prettyprinting a full snapshot of
it onto such a volume; and also the compiler will produce
a compiled disk file upon request.  One thinks of these as information
interchange media, rather than as the real source of the programs
contained therein.

The paramount issue, as raised by ALAN, is that in the MIT world,
one just never, but never, allows the machine-generated prettyprint
of his functions to be stored on disk file, or to be used for much
of anything other than casual inspection at the terminal.  Even
the style of editing isn't the critical factor (at lest for Interlisp-D
users -- tant pis for Interlisp-10), for there is a moderately good
E-style input buffer (E is the Standford editor which inspired EMACS)
called TTYIN.

In fact, I'd like to take this opportunity to praise the Display-based
structure editor of Interlisp-D, upon which I've become increasingly
dependent recently.  The combination of bitmap-display, multiple-fonts,
interface to old-style Interlisp structure editor, mouse-oriented
new-style operations, TTYIN keyboard interface, and so on, make this
the best editor by far, for LISP programs and data, of all those I've
ever seen.

Footnote:  there were a few comments about how semi-colon comments
    are "lost" by the READer; in Interlisp, the corresponding notion
    is asterisk comments, and the are not lost, but incorporated bodily
    intot he source code.  This has two implications: the reader's
    macrocharacter scheme is modified so taht 'FOO reads in as (QUOTE FOO)
    but Don't reads in as a 5-character symbol.  The second is that you
    can't bput comments just anywhere you please; e.g.
        (CONS X (* This is a comment about X.)
              Y)
    is wrong.  I've ocasionally resorted to kludges like
        (CONS (PROG1 X (* This is a comment about X.))
               Y)
    At least the prettyprinter moves comments over to a "comment
    column", just as the MacLisp GRINDEF would put semi-colon
    comments over in a comment column.
 

∂17-Nov-82  1359	JONL at PARC-MAXC 	What's wrong with '#,<frob> ?  
Date: 17 NOV 1982 1357-PST
From: JONL at PARC-MAXC
Subject: What's wrong with '#,<frob> ?
To:   common-lisp at SU-AI

As GSB related, the Maclisp notion of #, centers around a hokey
notion of "reading for the purpose of compiling this function", as
opposed to reading for any other purpose.  The probelm as I see it
is that QUOTE is being squeezed a bit beyond its capabilities.

QUOTE should imply a constant which is constant over all incarnations
of Lisp, and throughout all time.  The #, indicates something
which varies on a per-loadup basis, but is constant after that.
Previous to "#,", users would just set aside a global variable 
which would be initialized a load up time.  But I much prefer
    (MUMBLE-UPON X '(SOME #,(machine-name) MESSAGES))
to the less apealing
    (MUMBLE-UPON X GLOBALVARIABLE.FOR.MSG.FUNCTION.A0025)

Suggestion:  a new special form, say CQUOTE, which is like QUOTE
    but actually processes over its form, looking for
    certain substitutions to make (such as evaluating some part).
    this is hardly a new idea, since Adolfo Guzeman had such a
    macro in his PhD Thesis program in 1967 (running on a PDP6
    at that -- R.I.P. PDP6!)  Thus the above example would become
        (MUMBLE-UPON X (CQUOTE (SOME (:, (machine-name)) MESSAGES))
    or, if you will permit me the a few # macrocharacter extensions,
        (MUMBLE-UPON X #!(SOME #,(machine-name) MESSAGES))

There are problems to be worked out about whether the processing is
to happen at read time, at compile time, at load time, or at first
reference (Masinter's msg noted severl Interlisp special forms to make
these distinctions).  But it does bring some of the burden for
identifying an "evaluation context" for data back to the original user.

I might add, in addendum to GSB's note, the Bob Kerns and I worked
a long time at trying to get the compiler/assembler to "percolate"
information about squids u p from the inner guts of quoted data
to some "higher" level so that FASLOAD wouldn't crap out because
the load-time evaluation wound up calling FASLOAD recursively.  [I dont
thnk we ever got it 100% right -- I believe I saw another Maclisp bug
report last summer which would have been explaind by this.  But
there is a point of diminishing returns of COMPLR development, and besides
the problem goes away if you cause the needed file to be loaded in
befor hand]

As ALAN mentioned, only the Maclisp version of backquote has the option
of guaranteeing to the user some interal structure of the output
of the backquote and comma macros -- and having some such guarantee
is crucial to having a "residential" system which doesn't keep the text
of all its sources internally.  So how about "conditionalquote", i.e.
CQUOTE, by analogy to the BQUOTE case?

∂17-Nov-82  1541	JONL at PARC-MAXC 	What's wrong with '#,<frob> ?  
Date: 17 NOV 1982 1357-PST
From: JONL at PARC-MAXC
Subject: What's wrong with '#,<frob> ?
To:   common-lisp at SU-AI

As GSB related, the Maclisp notion of #, centers around a hokey
notion of "reading for the purpose of compiling this function", as
opposed to reading for any other purpose.  The probelm as I see it
is that QUOTE is being squeezed a bit beyond its capabilities.

QUOTE should imply a constant which is constant over all incarnations
of Lisp, and throughout all time.  The #, indicates something
which varies on a per-loadup basis, but is constant after that.
Previous to "#,", users would just set aside a global variable 
which would be initialized a load up time.  But I much prefer
    (MUMBLE-UPON X '(SOME #,(machine-name) MESSAGES))
to the less apealing
    (MUMBLE-UPON X GLOBALVARIABLE.FOR.MSG.FUNCTION.A0025)

Suggestion:  a new special form, say CQUOTE, which is like QUOTE
    but actually processes over its form, looking for
    certain substitutions to make (such as evaluating some part).
    this is hardly a new idea, since Adolfo Guzeman had such a
    macro in his PhD Thesis program in 1967 (running on a PDP6
    at that -- R.I.P. PDP6!)  Thus the above example would become
        (MUMBLE-UPON X (CQUOTE (SOME (:, (machine-name)) MESSAGES))
    or, if you will permit me the a few # macrocharacter extensions,
        (MUMBLE-UPON X #!(SOME #,(machine-name) MESSAGES))

There are problems to be worked out about whether the processing is
to happen at read time, at compile time, at load time, or at first
reference (Masinter's msg noted severl Interlisp special forms to make
these distinctions).  But it does bring some of the burden for
identifying an "evaluation context" for data back to the original user.

I might add, in addendum to GSB's note, the Bob Kerns and I worked
a long time at trying to get the compiler/assembler to "percolate"
information about squids u p from the inner guts of quoted data
to some "higher" level so that FASLOAD wouldn't crap out because
the load-time evaluation wound up calling FASLOAD recursively.  [I dont
thnk we ever got it 100% right -- I believe I saw another Maclisp bug
report last summer which would have been explaind by this.  But
there is a point of diminishing returns of COMPLR development, and besides
the problem goes away if you cause the needed file to be loaded in
befor hand]

As ALAN mentioned, only the Maclisp version of backquote has the option
of guaranteeing to the user some interal structure of the output
of the backquote and comma macros -- and having some such guarantee
is crucial to having a "residential" system which doesn't keep the text
of all its sources internally.  So how about "conditionalquote", i.e.
CQUOTE, by analogy to the BQUOTE case?

∂17-Nov-82  2259	Dave Dyer       <DDYER at USC-ISIB> 	duplicate-p? 
Date: 17 Nov 1982 2259-PST
From: Dave Dyer       <DDYER at USC-ISIB>
Subject: duplicate-p?
To: common-lisp at SU-AI


 I have been getting a LOT of duplicate messages from this mailing list,
most recently I got a gratuitous extra copy of Hedrick's "multiple value"
query of Nov 13.

 Is anyone else also receiving this garbage?  Whose mailer is stuttering?
-------

∂17-Nov-82  2316	Dave Dyer       <DDYER at USC-ISIB> 	duplicate-p? 
Date: 17 Nov 1982 2259-PST
From: Dave Dyer       <DDYER at USC-ISIB>
Subject: duplicate-p?
To: common-lisp at SU-AI


 I have been getting a LOT of duplicate messages from this mailing list,
most recently I got a gratuitous extra copy of Hedrick's "multiple value"
query of Nov 13.

 Is anyone else also receiving this garbage?  Whose mailer is stuttering?
-------

∂18-Nov-82  0847	Masinter at PARC-MAXC 	Re: Masinter's remarks on #,    
Date: 18-Nov-82  8:47:44 PST (Thursday)
From: Masinter at PARC-MAXC
Subject: Re: Masinter's remarks on #,
In-reply-to: Guy.Steele's message of 16 November 1982 2129-EST (Tuesday)
To: Guy.Steele at CMU-CS-A
cc: common-lisp at SU-AI

While READ is many-to-one, most of the identifications are merely syntactic;
that is (x . (a b c)) and (x a b c) really are the same program fragment
as far as program semantics go, while #,X and 3  (when X=3) are semantically
different.

One test for the distinction between syntactic and semantic macro characters is
whether READ = READ-PRINT-(new environment)-READ. The difficult cases then
remain #+ #- #.  and #,. 

Larry

∂19-Nov-82  1904	Glenn S. Burke <GSB at MIT-ML> 	named lambdas
Date: 19 November 1982 21:54-EST
From: Glenn S. Burke <GSB at MIT-ML>
Subject: named lambdas
To: common-lisp at SU-AI

In NIL, a subr (compiled-code object) is the only thing which is allowed
to go into a function cell.  There is mediation performed by FSET to
handle this.  SUBRs for compiled functions have the function name in them.

Interpreted DEFUN does an FSET of the name to an interpreter-closure,
which also has the function name in it.  FSYMEVAL on the name returns
the closure (not the trampoline subr).  Although FLET doesn't happen
to do this because it is currently a macro which expands into a different
NIL binding construct, it could be written as a special form which
also stored the name in the closure.

So, does FDEFINITION want to return the lambda expression of a defun,
or the closure?  Is it different from FSYMEVAL on a symbol?  Looks
like the function cell of your typical interpreted function is going
to have to have an interpreted-lexical-closure in it, so it looks like
everything of interest is going to be encapsulated somehow by
something which would be a more appropriate place for the name.

I'm not really trying to argue against named-lambdas.  That would be
hypocritical since i recently put them into NIL, although they haven't
been exercised and i may have missed a couple places (especially in
the compiler, but that's going away anyway).  But it seems that the
problem they solve might not actually occur that much now.

∂19-Nov-82  1940	MOON at SCRC-TENEX 	named lambdas  
Date: Friday, 19 November 1982  22:36-EST
From: MOON at SCRC-TENEX
To:   common-lisp at SU-AI
Subject: named lambdas
In-reply-to: The message of 19 Nov 1982 21:54-EST from Glenn S. Burke <GSB at MIT-ML>

FDEFINITION on a symbol should be the same as FSYMEVAL.

What you get if you do (PRINT (FDEFINITION foo)) necessarily has to be
implementation-dependent, it appears.  So in that sense NAMED-LAMBDA should
not be in Common Lisp, nor should LAMBDA.  Two exceptions to this:

The user should be given certain portable operations on functions,
including extracting their name.  In the case of interpreted functions it
should also be possible to extract the argument list and the body.

The user should be able to construct functions using more primitive
mechanisms than DEFUN.  One way to do this is to say that any list starting
with LAMBDA is acceptable as a function, and will be translated into
whatever the implementation wants.  Storing this function with FDEFINE and
then retrieving it with FDEFINITION will not, in general, return the same
object.  One could accept NAMED-LAMBDA at this level, too, although I like
JonL's idea for flushing it.  Another way would be to add a new primitive
MAKE-FUNCTION.

To do this right requires a portable specification of the behavior of
the interpreter's representation of a lexical environment.

∂19-Nov-82  1720	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	Named lambdas   
Date: Friday, 19 November 1982, 20:19-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: Named lambdas
To: Masinter at PARC-MAXC, common-lisp at SU-AI
In-reply-to: The message of 15 Nov 82 14:22-EST from Masinter at PARC-MAXC

    Date: 15-Nov-82 11:22:23 PST (Monday)
    From: Masinter at PARC-MAXC
    That the interpreter/compiled code forgets the name of the function you are
    executing in and/or the debugger has trouble finding it from looking at
    the stack seems more like a lack of functionality on the part of the debugger.
    Enough information is there to determine it 

Consider the following case:

(defun a (x y) ...)

(setq var (fdefinition 'a))

The value of var is now the definition of a, namely, the lambda expression
itself, or named-lambda expression on the Lisp Machine currently.

(funcall var 1 2)

At this point, suppose an error happens inside the body of a's
definition.  There is no way to tell that the function on the stack is
named "a" except because it says so inside it; currently, this is done
with named-lambda, although I agree that a stylized declaration could be
used instead.  But there's no way to get the name "a" from the surrounding
context.

I could come up with more involved cases, involving compiled functions
calling interpreted functions, but you get the idea.

∂22-Nov-82  0156	Kent M. Pitman <KMP at MIT-MC> 	a LAMBDA special form  
Date: 22 November 1982 04:55-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  a LAMBDA special form
To: MOON at SCRC-TENEX
cc: common-lisp at SU-AI

    Date: Friday, 19 November 1982  22:36-EST
    From: MOON at SCRC-TENEX
    To:   common-lisp at SU-AI
    Re:   named lambdas

    ... One way to do this is to say that any list starting with LAMBDA is
    acceptable as a function, and will be translated into whatever the
    implementation wants...

ie, LAMBDA should be a special form which returns a "function" (I use quotes
since I don't mean here an datatype, but rather an intension on a [possibly
already existing] datatype.) A typical system-dependent implementation being
something like
 (defmacro lambda (bvl &body body) `#'(lambda ,@body)).
Similarly for named-lambda.

I think this is a good idea.


    ... Another way would be to add a new primitive MAKE-FUNCTION ...

I would say this should be not so much an addition as possible extension.
The LAMBDA special form would have the interesting advantage of not needing
a preceeding #' and would still be statically analyzable by the compiler,
which is a decided advantage. But LAMBDA would not be as general (without
asking the user to call something like EVAL, which is obviously wrong).
So both are really called for.

∂22-Nov-82  1255	Masinter at PARC-MAXC 	Re: Named lambdas
Date: 22-Nov-82 12:54:20 PST (Monday)
From: Masinter at PARC-MAXC
Subject: Re: Named lambdas
In-reply-to: dlw at SCRC-TENEX's message of Friday, 19 November 1982, 20:19-EST
To: common-lisp at SU-AI

If you 

(defun a (x y) ..)

and then

(setf (fdefinition 'b) (fdefinition 'a))

and then call b, should it say you are inside a?

In lieu of any primitives or functions which manipulate these "names", it may
be moot whether the name is associated with "original definition" (i.e., what
you called defun with) or "call location" (i.e., where the definition came
from this time).

∂22-Nov-82  1459	MOON at SCRC-TENEX 	Re: Named lambdas   
Date: Monday, 22 November 1982  17:52-EST
From: MOON at SCRC-TENEX
To:   common-lisp at SU-AI
Subject: Re: Named lambdas
In-reply-to: The message of 22-Nov-82 12:54:20 PST () from Masinter at PARC-MAXC

    Date: 22-Nov-82 12:54:20 PST (Monday)
    From: Masinter at PARC-MAXC

    If you 
    (defun a (x y) ..)
    and then
    (setf (fdefinition 'b) (fdefinition 'a))
    and then call b, should it say you are inside a?

I say yes, because I believe that functions are first-class objects and
have names.  Thus the defun creates a function named a and then fdefine's
the symbol a to it.  The setf picks up that function and puts in another
cell as well.  But it's the same function.

∂22-Nov-82  1630	JONL at PARC-MAXC 	Re: Named lambdas    
Date: 22 NOV 1982 1630-PST
From: JONL at PARC-MAXC
Subject: Re: Named lambdas
To:   MOON at MIT-MC, common-lisp at SU-AI
cc:   JONL

In response to the message sent  Monday, 22 November 1982  17:52-EST from MOON@SCRC-TENEX

I like this analysis in your reply -- it finally puts some
sense into what has been a confusing notion, namely "nameing"
of functions.

If I may paraphrase, "functions" in the computer sense, i.e.
compiled-code objects, lambda expressions, closures, etc, may
have a name which is independent of any symbol to which that
"function" has been assigned (by fdefinition).  The name is more
like commentary on the code body, and would be helpful in
debugging.  Thus we could have 500 functions with  the "name"
FOO, and have 500 symbols all with the "same function" as
their functional definition.

Assignment of functions to symbols, via fdefinition, is a tool
of programming syntax, and nameing of functions is a tool of
user commentary?

∂01-Dec-82  0933	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	(↑ 0.0 0.0) AND (↑ 0 0.0) 
Date: Wednesday, 1 December 1982, 12:30-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: (↑ 0.0 0.0) AND (↑ 0 0.0)
To: common-lisp at su-ai
In-reply-to: The message of 1 Dec 82 02:03-EST from Alan Bawden <ALAN at SCRC-TENEX>

I want to forward this to the rest of you.  Common Lisp currently says
that zero to the zero is one, although it isn't careful about what data
types it's talking about; I assume that is means floating point.

    Date: Wednesday, 1 December 1982  02:03-EST
    From: Alan Bawden <ALAN at SCRC-TENEX>
    Just for the record let me clarify the issue about 0.0↑0.0 .  Consider
    taking the limit of A↑X as X approaches 0.0 (from above).  If A is
    different from 0.0 (and 0 as well incidentally), then the limit of this is
    1.0 .  On the other hand, if A=0.0 (or 0) then the limit is 0.0 .  Thus
    there would be a discontinuity of the function 0.0↑X (as well as 0↑X) at
    the point 0.0 if we were to decide that 0.0↑0.0 (and 0↑0.0) = 1.0 .
    Discontinuities in floating point functions are bad (as I understand the
    philosophy of floating point) because they mean that a small difference in
    floating point truncation and roundoff can be magnified arbitrarily.

∂01-Dec-82  1126	Kim.fateman@Berkeley
Date: 1-Dec-82 11:12:10-PST (Wed)
From: Kim.fateman@Berkeley
Message-Id: <8211011913.20885@UCBVAX.BERKELEY.ARPA>
Received: by UCBVAX.BERKELEY.ARPA (3.227 [10/22/82])
	id A20876; 1-Dec-82 11:13:07-PST (Wed)
To: dlw@scrc-tenex@mit-mc
Cc: common-lisp@su-ai

Awrighty, we've settled y↑0=1.  If you want to worry about these things, 
you have + and - infinity, in the IEEE arithmetic. You need to specify
inf↑(- inf)  = 0, 0↑(-infinity) = infinity, (or should that be a division
by zero?)  And if you've gotten all that set up, we can start talking
about accuracy. :-)

∂01-Dec-82  1412	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML> 	x↑0.0 
Date: Wednesday, 1 December 1982, 16:44-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-ML>
Subject: x↑0.0
To: Kim.fateman at UCB-C70
Cc: common-lisp at su-ai
In-reply-to: <8211011913.20888@UCBVAX.BERKELEY.ARPA>

    Date: 1-Dec-82 11:12:16-PST (Wed)
    From: Kim.fateman@Berkeley
    Awrighty, we've settled y↑0=1.  
I don't understand what you mean by this.  As far as I am concerned, we
have not necessarily settled on this; I think it might be a mistake to do so.
				    If you want to worry about these things, 
    you have + and - infinity, in the IEEE arithmetic.
Some implementations of Common Lisp will not have IEEE arithmetic, but
they will all have zero.  Even if we don't define all those weird
infinity cases, we should try to do the right thing for zeroes.  If you
are trying to tell me that I'm not allowed to discuss zeroes unless I
compose an entire essay on infinities, accuracy rules, and so on, I
disagree.

∂01-Dec-82  1513	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: x↑0.0    
Date:  1 Dec 1982 1810-EST
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: x↑0.0
To: dlw at SCRC-TENEX at MIT-MC
cc: Kim.fateman at UCB-C70, common-lisp at SU-AI
In-Reply-To: Your message of 1-Dec-82 1706-EST

I would like for any computation that doesn't have a well-defined value
to be either an error or result in some item which can never turn into a
normal number, even after being multiplied by 0.0. The problem with
things like +UNDEFINED is that when you multiply them by 0.0, you get
0.0.  But depending upon the exact expression involved and how you take
the limit, that is not necessarily a good result.  The problem with
+UNDEFINED or +INF is that you have only choices, neither of them very
attractive:
  - make them contagious. Any computation involving one of them
	produces a result that is either UNDEFINED or INF.  The problem
	there is that you can do an hour-long computation that
	returns UNDEFINED, and have no idea where the error occured.
  - make 0 * UNDEFINED = 0.  But that can result in meaningless answers.
It seems that you you supply, at least as an option, the ability to
generate an error whenever something questionable is happening.


-------

∂01-Dec-82  1530	HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility) 	Re: x↑0.0    
Date:  1 Dec 1982 1810-EST
From: HEDRICK at RUTGERS (Mgr DEC-20s/Dir LCSR Comp Facility)
Subject: Re: x↑0.0
To: dlw at SCRC-TENEX at MIT-MC
cc: Kim.fateman at UCB-C70, common-lisp at SU-AI
In-Reply-To: Your message of 1-Dec-82 1706-EST

I would like for any computation that doesn't have a well-defined value
to be either an error or result in some item which can never turn into a
normal number, even after being multiplied by 0.0. The problem with
things like +UNDEFINED is that when you multiply them by 0.0, you get
0.0.  But depending upon the exact expression involved and how you take
the limit, that is not necessarily a good result.  The problem with
+UNDEFINED or +INF is that you have only choices, neither of them very
attractive:
  - make them contagious. Any computation involving one of them
	produces a result that is either UNDEFINED or INF.  The problem
	there is that you can do an hour-long computation that
	returns UNDEFINED, and have no idea where the error occured.
  - make 0 * UNDEFINED = 0.  But that can result in meaningless answers.
It seems that you you supply, at least as an option, the ability to
generate an error whenever something questionable is happening.


-------

∂01-Dec-82  1822	Earl A. Killian <EAK at MIT-MC> 	function ballot  
Date: 1 December 1982 21:17-EST
From: Earl A. Killian <EAK at MIT-MC>
Subject: function ballot
To: common-lisp at SU-AI

Some time ago I sent out a message suggesting that a cons with
its car eq to lambda not be considered a function.  No one
replied negatively.  However, the issue was omitted from the
various ballots that were taken.  I'd really like to survey
peoples opinions on this, and remove this requirement from Common
Lisp if there is a consensus.

Briefly, as in Lisp 1.5, the Common Lisp manual currently
specifies that the LIST
	(lambda (x) (+ x 1))
is a function.  In particular, one can write
	(apply '(lambda (x) (+ x 1)) '(5))

I consider retaining this in Common Lisp to be a wart.  Common
Lisp programs should write
	(apply #'(lambda (x) (+ x 1)) '(5))
instead.  There are no advantages to allowing the list as a
function, except maybe compatibility.  There are disadvantages:
inefficiency, confusion (with respect to lexical scoping), and
needless complexity.  As far as compatibility goes, it is
completely minor, as the functionality still exists, just with a
minor syntax change, and most Maclisp programs already use #'.
Also, nothing prevents an implementation from supporting lists
beginning with lambda as functions: I am only suggesting that
portable Common Lisp programs not use this.

∂01-Dec-82  1838	Scott E. Fahlman <Fahlman at CMU-CS-C> 	function ballot
Date: Wednesday, 1 December 1982  21:38-EST
From: Scott E. Fahlman <Fahlman at CMU-CS-C>
To:   Earl A. Killian <EAK at MIT-MC>
Cc:   common-lisp at SU-AI
Subject: function ballot


EAK's suggestion sounds good to me.  In fact, our Spice implementation
makes rude noises at you if you put '(lambda ...) where #'(lambda...)
would be more appropriate.  (I guess the rude noises were a non-standard
extension in our implementation...)

I assume that this will not affect the evaluation of forms whose car is
a lambda expression.  That much tradition is too heavy to mess with.

-- Scott

∂01-Dec-82  1838	Earl A. Killian <EAK at MIT-MC> 	function ballot  
Date: 1 December 1982 21:17-EST
From: Earl A. Killian <EAK at MIT-MC>
Subject: function ballot
To: common-lisp at SU-AI

Some time ago I sent out a message suggesting that a cons with
its car eq to lambda not be considered a function.  No one
replied negatively.  However, the issue was omitted from the
various ballots that were taken.  I'd really like to survey
peoples opinions on this, and remove this requirement from Common
Lisp if there is a consensus.

Briefly, as in Lisp 1.5, the Common Lisp manual currently
specifies that the LIST
	(lambda (x) (+ x 1))
is a function.  In particular, one can write
	(apply '(lambda (x) (+ x 1)) '(5))

I consider retaining this in Common Lisp to be a wart.  Common
Lisp programs should write
	(apply #'(lambda (x) (+ x 1)) '(5))
instead.  There are no advantages to allowing the list as a
function, except maybe compatibility.  There are disadvantages:
inefficiency, confusion (with respect to lexical scoping), and
needless complexity.  As far as compatibility goes, it is
completely minor, as the functionality still exists, just with a
minor syntax change, and most Maclisp programs already use #'.
Also, nothing prevents an implementation from supporting lists
beginning with lambda as functions: I am only suggesting that
portable Common Lisp programs not use this.

∂01-Dec-82  1928	MOON at SCRC-TENEX 	function ballot
Date: Wednesday, 1 December 1982  22:16-EST
From: MOON at SCRC-TENEX
to:   common-lisp at SU-AI
Subject: function ballot
In-reply-to: The message of 1 Dec 1982  21:38-EST from Scott E. Fahlman <Fahlman at CMU-CS-C>

    Date: Wednesday, 1 December 1982  21:38-EST
    From: Scott E. Fahlman <Fahlman at CMU-CS-C>

    I assume that this will not affect the evaluation of forms whose car is
    a lambda expression.  That much tradition is too heavy to mess with.

Well, of COURSE not, since putting #' in front of something means "evaluate"
this as if it was the car of a form.  And I guess that forces me to agree with
EAK.

This means, of course, that you need a "subr version" of FUNCTION for use
by programs that used to construct functions by consing up lists whose
car was LAMBDA.  It should take an optional argument which is an environment
which means, of course, that an interpreter-environment data type has to
be added to the language.

∂01-Dec-82  2306	Guy.Steele at CMU-CS-A 	More on 0↑0
Date:  2 December 1982 0205-EST (Thursday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: More on 0↑0

If you take the limit of x↑x as x approaches 0 from the northeast
(that is, taking on values of the form q+iq where q is real), then,
according to my calculations, the limit is e↑(-sqrt(2)*pi/8+sqrt(2)*pi/8*i)
which is approximately 0.4876+.30275i.  Ain't that a kick in he head???
--Guy

∂01-Dec-82  2304	Guy.Steele at CMU-CS-A 	0↑0   
Date:  2 December 1982 0154-EST (Thursday)
From: Guy.Steele at CMU-CS-A
To: common-lisp at SU-AI
Subject: 0↑0

Here's the scoop!  The exponentiation function has an essential singularity
at (0,0).  You can get 0↑0 to equal any of an infinite number of values
by causing the limit to be computed by an approach from an appropriate
direction.  For example, LIM [x->0] x↑x = 1 if x approaches 0 along
the real axis; but if it approaches along the imaginary axis, the limit
is e↑(-pi/2), if I have done my calculations correctly.

Many languages define 0↑0=1 because that preserves a number of interesting
identities that are more useful in practice than 0↑x=0.  Kahan agrees with
that in his latest paper on branch cuts.

Kahan further assumes that, in languages that distinguish between 0 and 0.0
(which APL does not), the value 0 is likely to be exact, whereas the 0.0
might be exact or might be ther result of underflow.  This is why he
recommends 0↑0 = 0.0↑0 = 1 but 0.0↑0 = 0.0↑0.0 = error, because if the exponent
is the result of underflow then you get an anomaly; if only that
underflowed value had been preserved (call it EPS), then 0.0↑EPS = 0.0,
not 1, and you don't want the problem of underflow to cause discontinuities
in the result.

On the other hand, I observe that there is an essential problem here: you
just can't tell whether a 0.0 is an exact value or not.  I am inclined
to let any zero raised to any zero be 1 or 1.0, as appropriate, in Common LISP.
--Guy

∂02-Dec-82  0404	JONL at PARC-MAXC 	Re: x↑0.0  
Date:  2 DEC 1982 0406-PST
From: JONL at PARC-MAXC
Subject: Re: x↑0.0
To:   HEDRICK at RUTGERS, dlw at MIT-AI
cc:   Kim.fateman at UCB-C70, common-lisp at SU-AI, JONL

In response to the message sent   1 Dec 1982 1810-EST from HEDRICK@RUTGERS 

I'm not sure that you really do have *two* choices;  INF has to 
have certain properties, such as being larger in magnitude than
any other (non-INF) number, and being an additive sink.  Similarly,
UNDEFINED has to be an operative sink;  trying to make an exception
for zero seems to lead to another of those discontinuities like
0↑0 = 0.

But I certainly agree that a user-settable option calling for an
error upon generation of UNDEFINED would be a good idea.

∂02-Dec-82  0502	JONL at PARC-MAXC 	Speaking of issues left of the Ballots ...    
Date:  2 DEC 1982 0504-PST
From: JONL at PARC-MAXC
Subject: Speaking of issues left of the Ballots ...
To:   common-lisp at SU-AI

At the meeting in August, I mentioned that LOAD-BYTE and DEPOSIT-BYTE
had been dropped without discussion.  Around that time also,
EAK and I offered reasons why they are better choices than LDB and
DPB.  I hope that after considering them, you'll feel more inclined
to at least include LOAD-BYTE in the white pages, regardless of the
status of LDB.

1) LDB presents us with a fatal flaw -- either we break compatibility
   with the LispMachine definition (and the PDP10 MacLisp definition)
   or we are stuck with a primitive which cant address more than 63
   bits worth of byte, nor any bits beyond the 64'th.  Despite the
   manual's best intention of abstracting the notion of a "byte
   specifier" (section 12.7), the LispM/MacLisp practice is to use a
   4-digit octal number.  When, in existing code, the bytespec
   isn't the PDP-10 determined 4 octal digits (say, some variable)
   then a mechanical converter *cant't* turn that code into
   the use of the BYTE function (unless "byte specifiers" are a new
   data type which will be type-certified by each use of LDB; for
   if such a conversion happened with out type-integrity, then assuming
   that a "byte specifier" is still some integer, there would be
   no guarantee that the conversion wasn't happening on an integer
   already converted elsewhere.

2) LDB and LOAD-BYTE tend to treat ingeters as sequences; as such, the
   syntax of subsequence specification is totally out of character with
   the other sequence functions.  At the very least, we should have
   (INTEGER-SUBSEQ <n> <start-position> &optional <end-position>)
   which would translate into something like a currently-defined LDB
   with bytespec of (BYTE (1+ (- <start> <end>)) <start>).  It may be
   that I've forgotten EAK's original complaint against LDB, but I
   thought it was essentially this.

3) the name Lid-ub (or Ell-dib, if you prefer) is the worst asssault on
   the reasonableness of names in the CommonLisp lexicon.  Who, who
   hasn't been contaminated with PDP10 lore, would think this an
   appropriate name?  How can a community as sensitive to the 
   implications of nomenclature as to change "haulong" into 
   "integer-length" not be swayed to prefer "integer-subseq" to L.D.B. 

∂03-Dec-82  1102	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	0↑0   
Date: Friday, 3 December 1982, 12:51-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: 0↑0
To: Guy.Steele at CMU-CS-A, common-lisp at SU-AI
In-reply-to: The message of 2 Dec 82 01:54-EST from Guy.Steele at CMU-CS-A

    Date:  2 December 1982 0154-EST (Thursday)
    From: Guy.Steele at CMU-CS-A
    Kahan further assumes that, in languages that distinguish between 0 and 0.0
    (which APL does not), the value 0 is likely to be exact, whereas the 0.0
    might be exact or might be ther result of underflow.
Yes, this is exactly what Alan said.

    On the other hand, I observe that there is an essential problem here: you
    just can't tell whether a 0.0 is an exact value or not.  I am inclined
    to let any zero raised to any zero be 1 or 1.0, as appropriate, in Common LISP.
It seems you are erring more on the side of danger than safety.  I
think I agree with Kahan.

∂03-Dec-82  1102	Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC> 	function ballot 
Date: Friday, 3 December 1982, 12:54-EST
From: Daniel L. Weinreb <dlw at SCRC-TENEX at MIT-MC>
Subject: function ballot
To: MOON at SCRC-TENEX at MIT-MC, common-lisp at SU-AI
In-reply-to: The message of 1 Dec 82 22:16-EST from MOON at SCRC-TENEX

    Date: Wednesday, 1 December 1982  22:16-EST
    From: MOON at SCRC-TENEX
    This means, of course, that you need a "subr version" of FUNCTION for use
    by programs that used to construct functions by consing up lists whose
    car was LAMBDA.  
I think that the later schemes had such a function, called ENCLOSE or something.
		     It should take an optional argument which is an environment
    which means, of course, that an interpreter-environment data type has to
    be added to the language.
Can we use the thing that *EVAL takes for this purpose?

∂03-Dec-82  1451	Kent M. Pitman <KMP at MIT-MC> 	ENCLOSE and EVAL  
Date: 3 December 1982 17:50-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject:  ENCLOSE and EVAL
To: dlw at SCRC-TENEX
cc: COMMON-LISP at SU-AI, Guy.Steele at CMU-CS-A

I wrote an ENCLOSE for an early simulator of T and I forgot to put in the
check for LAMBDA-ness and found out that if you did (ENCLOSE '(+ 5 1)) you
got back 6, which is maybe suggestive of something. After all, what's the
difference between (ENCLOSE '(LAMBDA (X) X)) and (EVAL '(LAMBDA (X) X))?
Answer: nothing. Only that ENCLOSE looks like:
 (DEFUN ENCLOSE (LAMBDA-EXP &OPTIONAL (ENV *THE-TOPLEVEL-ENVIRONMENT*))
   (CHECK-ARG ...lambda-expression-p of LAMBDA-EXP...)
   (*EVAL LAMBDA-EXP ENV))
If you are not going to put EVAL or *EVAL in the language, I'd definitely
say something along the lines of ENCLOSE would be a good idea because it
constraints things a bit. Since EVAL and/or *EVAL will be there, I'd say
ENCLOSE may still be notationally useful because this is a very constrained
kind of EVAL. eg, SYMEVAL is nice for the same reason. EVAL could do its
work, but somehow it doesn't feel like you're letting loose the full
unconstrained hair of the language by calling it in the same way as you 
would if you called EVAL.

Since Guy was in on Scheme's replacement of EVAL with ENCLOSE, perhaps he
could comment on my conclusions here...?


∂03-Dec-82  1502	Guy.Steele at CMU-CS-A 	Re: ENCLOSE and EVAL 
Date:  3 December 1982 1754-EST (Friday)
From: Guy.Steele at CMU-CS-A
To: Kent M. Pitman <KMP at MIT-MC>
Subject: Re: ENCLOSE and EVAL
CC: common-lisp at SU-AI
In-Reply-To: Kent M. Pitman's message of 3 Dec 82 17:47-EST

Indeed, ENCLOSE is what the evaluator uses to handle the evaluation
of a LAMBDA-expression.  So one may be defined using the other.
--Guy

∂03-Dec-82  1513	Kent M. Pitman <KMP at MIT-MC> 	EAK's fuction ballot   
Date: 3 December 1982 18:02-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject: EAK's fuction ballot
To: EAK at MIT-MC
cc: common-Lisp at SU-AI

Common-Lisp should define only the things we want and need to write 
clean, transportable code. There are already a sufficient number of
things changed from existing dialects that code will have to be 
reviewed before it will run in Common-Lisp. As such, I think it's
appropriate and desirable that we leave (apply '(lambda ...) ...)
undefined and guarantee only that APPLYing #'(lambda ...) will work.
I would advocate in the red pages that language implementors try to
phase out the old '(lambda ...) notation, but we could just leave that
undefined in the white pages for now so that implementations would have 
the option of retaining backward compatibility for now at their individual
discretion. 
--kmp

∂03-Dec-82  1538	Kent M. Pitman <KMP at MIT-MC> 	EAK's fuction ballot   
Date: 3 December 1982 18:02-EST
From: Kent M. Pitman <KMP at MIT-MC>
Subject: EAK's fuction ballot
To: EAK at MIT-MC
cc: common-Lisp at SU-AI

Common-Lisp should define only the things we want and need to write 
clean, transportable code. There are already a sufficient number of
things changed from existing dialects that code will have to be 
reviewed before it will run in Common-Lisp. As such, I think it's
appropriate and desirable that we leave (apply '(lambda ...) ...)
undefined and guarantee only that APPLYing #'(lambda ...) will work.
I would advocate in the red pages that language implementors try to
phase out the old '(lambda ...) notation, but we could just leave that
undefined in the white pages for now so that implementations would have 
the option of retaining backward compatibility for now at their individual
discretion. 
--kmp

∂03-Dec-82  1603	Eric Benson <BENSON at UTAH-20> 	Re: EAK's fuction ballot   
Date:  3 Dec 1982 1659-MST
From: Eric Benson <BENSON at UTAH-20>
Subject: Re: EAK's fuction ballot
To: KMP at MIT-MC, EAK at MIT-MC
cc: common-Lisp at SU-AI
In-Reply-To: Your message of 3-Dec-82 1602-MST

What about
(APPLY 'FOO ...)
as opposed to
(APPLY #'FOO ...)?
Also, in the following:

(DEFUN FOO ()
  1)

(DEFUN BAR ()
  (FUNCALL #'FOO)

(DEFUN FOO ()
  2)

does (BAR) return 1 or 2?  2 is consistent with the assumption that
#'... is treated the same as the CAR of a form.  ENCLOSE would
presumably have (BAR) returning 1, however.
-------

∂04-Dec-82  1505	Earl A. Killian <EAK at MIT-MC> 	bit-vectors 
Date: 4 December 1982 18:06-EST
From: Earl A. Killian <EAK at MIT-MC>
Subject: bit-vectors
To: common-lisp at SU-AI

Moon once sent a message asking why Common Lisp had both
bit-vectors and bignums, since many operations on bit-vectors
exist in other forms for integers.  No one really answered him,
as I remember.  Where does this issue stand?

∂04-Dec-82  1511	Earl A. Killian <EAK at MIT-MC> 	` and '
Date: 4 December 1982 18:13-EST
From: Earl A. Killian <EAK at MIT-MC>
Subject: ` and '
To: common-lisp at SU-AI

Is there any reason to have ` and ' actually be separate
characters?  Presumably `(a b c) could read in as (quote (a b c))
because there are no commas in it.  Is there some cognitive
advantage to keeping them separate, or is it simply a distinction
that derives from the historical development of Maclisp?

∂04-Dec-82  1522	Alan Bawden <ALAN at MIT-MC> 	` and '   
Date: 4 December 1982 18:23-EST
From: Alan Bawden <ALAN at MIT-MC>
Subject:  ` and '
To: EAK at MIT-MC
cc: common-lisp at SU-AI

Yes there is a very good reason to keep ` and ' distinct.  Consider
something like:

(defmacro foo-bar-or-else-p (x y)
  `(memq ,x '(foo bar ,y)))

∂04-Dec-82  1739	George J. Carrette <GJC at MIT-MC> 	bitvectors verses bignums    
Date: 4 December 1982 20:37-EST
From: George J. Carrette <GJC at MIT-MC>
Subject:  bitvectors verses bignums
To: EAK at MIT-MC
cc: COMMON-LISP at SU-AI

MOON's original note pointed out that no side-effecting operations
had been given at the time for bitvectors. This was a fairly
silly oversight, now fixed.

In any case there is a subtle difference between them, the meaning
of the LENGTH. You can have a bitvector 100 bits long, with all bits zero,
but you cannot have a number 100 bits long which is 0.

-GJC

p.s. On the lexical-scoping issue: I am working on a note summarizing 
     USER-EXPERIENCE and comments collected over the last year that the 
     "hail-mary" versions of NIL have been in use, since lexical-scoping
     caused the most people the most problems.