[comp.lang.lisp] DeKleer's ATMS: the continuing saga

burke@pollux.usc.edu (Sean Burke) (08/18/89)

As regards my previous posting, persons with similar problems using the
the code walke are advised to get the latest version of this code
from the PCL distribution, which contains a system-specific clause
for Coral Common Lisp.  Gregor.pa@Xerox.com advises me that an improved
version of the walker will be appearing in a month or so.  The clause
for CCL follows:

  #+:CORAL                      (ccl::proclaimed-special-p symbol)

  That is not the end of it though.  The n-queens example in example.lisp
calls create-consumer, a macro which is defined as follows:

;;;**** consumer-constructor-macro unnecessary.*** now.
(defmacro create-consumer (name arguments &rest variables)
  `(create-consumer-internal 
      ',name ,arguments (,(intern (format nil "~A-MACRO" name))	,@variables)))

  This macro expansion would transform the call

	(create-consumer N-QUEENS (list (aref queens j) (aref queens i)))))
to
	(create-consumer-internal 'n-queens (...) (|n-queens-MACRO|))

which breaks trying to eval (|n-queens-MACRO), which is naturally an unbound
function.  I'm completely at a loss as to what's going on here.  This should
not work on any common lisp.  The comment implies that this macro is no
longer needed,  but it's still referenced in many places.

  Another wierd thing is that create-consumer-internal calls 
new-add-conjunctive-[node class]-consumer indirectly, which contain a call to
create-consumer.  I wonder if this would plunge into infinite recursion.

  As always, I'm open to any hints.

  Sean

"The nice thing about true hopelessness
 is that you don't have to try again" - Jules Shear

burke@pollux.usc.edu (Sean Burke) (08/29/89)

  OK, I've got the real story, up to now!  Espen Vestre, in the Math dept of
the university of Oslo inn Norway, made an important observation:

>> ;;;**** consumer-constructor-macro unnecessary.*** now.
>> (defmacro create-consumer (name arguments &rest variables)
>>   `(create-consumer-internal 
>>       ',name ,arguments (,(intern (format nil "~A-MACRO" name))
>>			    ,@variables)))
>> 
>>   This macro expansion would transform the call
>> 
>> 	(create-consumer N-QUEENS (list (aref queens j) (aref queens i)))))
>> to
>> 	(create-consumer-internal 'n-queens (...) (|n-queens-MACRO|))
>> 
>> which breaks trying to eval (|n-queens-MACRO),
>
>What's going on here??  According to Common Lisp standards, the format
>statement should use the print name of the atom N-QUEENS which of course is
>N-QUEENS and not n-queens.  So you should have gotten N-QUEENS-MACRO instead
>of |n-queens-MACRO|.  I tried it on my own Allegro CL for the mac, and I
>got the right, capitilized version.

  I am using version 1.2.2 of CCL.  Here's an example of how print-names and 
format behave in this version:

1 > (setq y 'FOO)
foo
1 > y
foo
1 > (symbol-name y)
"FOO"
1 > y
foo
1 > (string y)
"FOO"
1 > (format nil "~A" y)
"foo"

  As you can see, the atom y seems to have two print-names, depending on the
context, and format seems be in the second category.  CCL seems to have a 
policy of lower casing all atoms typed in by the user, I suppose because
programmers usually write lisp in lower case and want to see lower case in
debuggers and inspectors.  It seems as if the print name is converted to 
upper case only for the purpose of looking up symbol bindings. Whether this
is orthodox Common Lisp I cannot say.

As it turns out, the binding for n-queens-macro is made with the statement:

	(intern (concatenate 'STRING names "-MACRO"))

whereas we later try to reference this atom via 

	(intern (format nil "~A-MACRO" name))

Because format behaves differently than string when choosing whether to print
an atom's name in upper or lower case, and because intern helpfully escapes
non-standard symbol names, e.g.

1 > (intern "ooF")
|ooF|
nil

then we create a new symbol instead.

   It took me a while to figure this out. This is because I had also failed to
give the (in-package 'tms) directive before running the example.  As a result,
the second call to intern creates a symbol in the USER package, whereas the
first call, executed in the load-time environment, puts its definition into
the package TMS, because there is an (in-package ) form at the top of the file.

   So, the fix for CCL is to convert the intern form in the create-consumer
macro above (cons3.lisp) to:

	(intern (format nil "~A-MACRO" (symbol-name name)) 'tms)

which creates an uppercase print-name and also specifies the package 'tms,
since we wish to reference the atom which already exists in this package.
This fix allows the n-queens demo to run with gratifying speed on my Mac+.

   I have looked in vain in CLTL for a specification that format should use
the canonical print-name of a symbol, unless you count p304, "To get the string
representation of a number or any other Lisp object, use prin1-to-string,
princ-to-string, or format."  The functions which are specified to return
a symbol's print-name, "symbol-name" and "string" get no mention. Hmmm.

   One is continually reminded that C.L. is a very complex language, something
we don't always admit when proselytizing.  Hopefully there is a better way of
doing what deKleer is doing here, since the integrity of this particular 
implementation hangs by a thread.

Sean Burke

"The nice thing about true hopelessness
 is that you don't have to try again" - Jules Shear

uda@majestix.ida.liu.se (Ulf Dahlen) (08/30/89)

In article <19543@usc.edu> burke@pollux.usc.edu (Sean Burke) writes:
>   I have looked in vain in CLTL for a specification that format should use
>the canonical print-name of a symbol, unless you count p304, "To get the string
>representation of a number or any other Lisp object, use prin1-to-string,
>princ-to-string, or format."  The functions which are specified to return
>a symbol's print-name, "symbol-name" and "string" get no mention. Hmmm.

In CLtL page 387 the ~A directive to FORMAT is explained. It says the 
the argument is printed without escape characters, as by PRINC. (Compare
~S where the argument is printed as by prin1 instead.)

So, you would expect (FORMAT nil "~A" 'foo) to return a string with FOO
as printed by PRINC. Now, all printing functions are governed by a couple
of variables, one of them beeing *PRINT-CASE*. If *PRINT-CASE* is :UPCASE
symbols will be printed in upper-case, if it's :DOWNCASE symbols will be 
printed in lower-case.

Binding *PRINT-CASE* to :UPCASE around the FORMAT should work. However,
a better solution is (FORMAT nil "~A" (STRING 'FOO)) which will always
give the internal print-name of FOO.
__________
Ulf Dahlen
Dept of Computer & Info Science, University of Linkoping, Sweden
Troskaregatan 51:23       |     uda@ida.liu.se
S-583 30  LINKOPING       |     uda@majestix.liu.se, uda@liuida.UUCP
SWEDEN                    |     {mcvax,munnari,seismo}!enea!liuida!uda
"The beginning is a very delicate time."

alms@cambridge.apple.com (Andrew L. M. Shalit) (08/31/89)

  ...
     As you can see, the atom y seems to have two print-names, depending on the
   context, and format seems be in the second category.  CCL seems to have a 
   policy of lower casing all atoms typed in by the user, I suppose because
   programmers usually write lisp in lower case and want to see lower case in
   debuggers and inspectors.  It seems as if the print name is converted to 
   upper case only for the purpose of looking up symbol bindings. Whether this
   is orthodox Common Lisp I cannot say.
   ...
      I have looked in vain in CLTL for a specification that format should use
   the canonical print-name of a symbol, unless you count p304, "To get the
   string representation of a number or any other Lisp object, use
   prin1-to-string, princ-to-string, or format."  The functions which are
   specified to return a symbol's print-name, "symbol-name" and "string" get
   no mention. Hmmm.
   ...

Check out the variable *print-case*.  If *PRINT-CASE* is :UPCASE, then
symbols are printed in upper-case.  If it's :DOWNCASE, then symbols are
printed in lower-case.  It looks like someone is setting the value of
*PRINT-CASE* to :DOWNCASE in your init file.