From: kevin gallagher
Subject: Re: string to symbol conversion
Date: 
Message-ID: <32436@dime.cs.umass.edu>
My previous note may have left an erroneous perception, namely, that
there is something wrong with READ-FROM-STRING.  The potential bug I
alluded to is due to the expectation (in the context of the original
question) that the particular use of READ-FROM-STRING will return a
symbol.  In fact, READ-FROM-STRING can return any datatype and your
program will break if you expect a symbol.  (Additionally, because of
read macros, READ-FROM-STRING can *do* anything.  It might not even
return at all.)

If you use INTERN you will be assured of getting back a symbol.

From: Mitchell Marks
Subject: Re: string to symbol conversion
Date: 
Message-ID: <MITCHELL.91Jun24110054@gluttony.uchicago.edu>
Here is a set of general purpose functions and variations on this
theme.  The handling of packages involves some iffy choices, but I
think the rest is fairly solid.

---------------- clip here --------------------

;;; SYMCAT takes one or more constituents (each of which must be either a
;;; symbol, a string, or a nonnegative fixnum) and returns a symbol whose
;;; name is made by concatenating the printnames (for symbols) or contents
;;; (for strings) of the arguments, in the order given, with no separator.
;;; The new symbol is interned in the home package of the first
;;; constituent, if that constituent is a symbol, or else in the current
;;; package (value of *PACKAGE*) if the first constituent is a string.

(defun symcat (&rest syms)
  (insist symcat (not (null syms)))
  (symcat-symlist syms))

;;; SYMCAT-SEPARATE takes a separator string (or symbol) and one or more
;;; constituents (symbols, strings, or natural numbers).  It returns a
;;; symbol whose name consists of the printnames (of the symbols) or
;;; contents (of the strings) of the constituent arguments, with the
;;; separator inserted in between each succcessive symbol or string.  The
;;; separator is not added before the first nor after the last of the
;;; constituent arguments; and if there is only one constituent, the
;;; separator is not used at all.  The new symbol is interned in the home
;;; package of the first constituent, if that constituent is a symbol, or
;;; else in the current package (value of *PACKAGE*) if the first
;;; constituent is a string.

;;; SYMCAT-SEPARATE-AUX does the work of SYMCAT-SEPARATE, but takes the
;;; constituents in a list instead of an &rest argument; this makes it
;;; suitable for use by the predefined-separator functions.  The test for
;;; null constituent list cannot be left to the lower-level functions,
;;; since at least one implementation (ACL 3.2) tends to come up with the
;;; symbol NIL.

(defun symcat-separate (separator &rest constituents)
  (symcat-separate-aux separator constituents))

(defun symcat-separate-aux (separator constituents)
  (insist symcat-separate-aux 
          (not (null constituents))
          (or (symbolp separator) (stringp separator) (natnump separator)))
  (symcat-symlist 
   (cons (car constituents)
         (symcat-interleave separator (cdr constituents)))))

(defun symcat-interleave (separator constituents)
  (if (null constituents)
      nil
    (cons separator 
          (cons (car constituents)
                (symcat-interleave separator (cdr constituents))))))

;;; The functions SYMCAT-HYPHEN, SYMCAT-STAR, SYMCAT-EQUAL, SYMCAT-PLUS,
;;; SYMCAT-DOT, and SYMCAT-SPACE provide the functionality of
;;; SYMCAT-SEPARATE with predefined separators.  Each takes one or more
;;; arguments, which must each be a symbol or string.  

(defun symcat-hyphen (&rest constituents)
  (symcat-separate-aux "-" constituents))

(defun symcat-star (&rest constituents)
  (symcat-separate-aux "*" constituents))

(defun symcat-equal (&rest constituents)
  (symcat-separate-aux "=" constituents))

(defun symcat-plus (&rest constituents)
  (symcat-separate-aux "+" constituents))

(defun symcat-dot (&rest constituents)
  (symcat-separate-aux "." constituents))

(defun symcat-space (&rest constituents)
  (symcat-separate-aux " " constituents))



;;; SYMCAT-INTERN is the low-level function ultimately called by all the
;;; higher-level functions defined here; it's the place where INTERN gets
;;; used. The argument SYMLIST must be a non-null list of symbols or
;;; strings, and the argument PKG must be a package.

(defun symcat-intern (symlist pkg)
  (insist symcat-intern 
          (not (null symlist)) 
          (packagep pkg))
  (intern (apply #'concatenate 'string
                 (for (item :in symlist)
                      :save (stringify item)))
          pkg))

(defun stringify (item)
  (cond ((stringp item) item)
        ((symbolp item) (string item))
        ((natnump item) (format nil "~d" item))
        (t (error  "~s is not a string, symbol, or natural number" item))))

(defun natnump (item)
  (and (integerp item) (not (minusp item))))

;;; SYMCAT-SYMLIST feeds SYMCAT-INTERN.  The argument SYMLIST must be a
;;; nonnull list of symbols, strings, or naturalnumbers.  The function
;;; determines the package into which the new symbol should be interned,
;;; based on the first member of SYMLIST: if this member is a symbol, its
;;; home package is used, otherwise the current package (value of
;;; *PACKAGE*) is used.

(defun symcat-symlist (symlist)
  (insist symcat-symlist (not (null symlist)))
  (for (item :in symlist)
       :do (if (not (or (symbolp item) (stringp item) (natnump item)))
               (error "~s is not a string, symbol, or natural number" item)))
  (let ((pkg (if (symbolp (car symlist))
                 (symbol-package (car symlist))
               *package*)))
    (symcat-intern symlist pkg)))


;;; -----------------------------------------------
#|
  Oops, I see this uses INSIST; well, it follows:
|#
;;; -----------------------------------------------

#|
The INSIST macro provides a way of embedding assertions in code, and
raising an error when they are not met.  This can aid in debugging semantic
errors which otherwise do not immediately produce a LISP error.

The definition is taken from Inside Case-Based Reasoning.

The form is

  ( INSIST <name> <expression>* )

The <name> is a symbol which will not be evaluated, and should normally be
the name of the function (etc) within whose definition the INSIST form
appears. Each <expression> will be evaluated, and an error will be raised
if one evaluates to NIL.

Example:

(defun numeric-function (a b)
  (insist numeric-function (numberp a) (numberp b))
  (+ a (* 5 b)))

<cl 8> (numeric-function 4 5)

29 
<cl 9> (numeric-function 5 'z)
Error: (NUMBERP B) failed in NUMERIC-FUNCTION
[1] <cl 10> 

|#


(defmacro insist (fnname &rest exps)
 `(and ,@(make-insist-forms fnname exps)))

(defun make-insist-forms (fnname exps)
 (and (not (null exps))
      (cons `(or ,(car exps)
                 (error "~s failed in ~s"
                        ',(car exps) ',fnname))
            (make-insist-forms fnname (cdr exps)))))


--
Mitch Marks    ········@cs.UChicago.EDU
  --But...but...I can see with my own two eyes that it's...
  --Hey, who're you gonna believe: *me* or your own two eyes?
From: Bill Andersen
Subject: INSIST Macro (was:Re: string to symbol conversion)
Date: 
Message-ID: <36066@mimsy.umd.edu>
  I noticed the INSIST macro in your SYMCAT code.  Why use this when
you can just use CL's ASSERT?  The function of ASSERT is to allow
programmers to insert arbitrary tests into their functions to guard
against bad arguments, etc.  I pointed this out to another UChicago
person and he agreed with me.  This macro is all over the place in
Schank & Riesbeck's "Inside Case Based Reasoning" so I assume that's
how it migrated to UChicago (via Hammond & others).

--
    Bill Andersen (·······@cs.umd.edu) |
    University of Maryland             | clever .signature saying
    Department of Computer Science     | under construction
    College Park, Maryland  20742      |
From: Mitchell Marks
Subject: Re: INSIST Macro (was: Re: string to symbol conversion)
Date: 
Message-ID: <MITCHELL.91Jun29115212@gluttony.uchicago.edu>
>>>>> "ba" == Bill Andersen <·······@flubber.cs.umd.edu> writes:


  ba>   I noticed the INSIST macro in your SYMCAT code.  Why use this
  ba> when you can just use CL's ASSERT?

For thoroughly uninteresting personal/historical reasons: at the time,
I wasn't aware of ASSERT, and had recently come across INSIST and was
using it everywhere for about a week.

  ba> The function of ASSERT is to allow programmers to insert
  ba> arbitrary tests into their functions to guard against bad
  ba> arguments, etc.  I pointed this out to another UChicago person
  ba> and he agreed with me.

And so do I, mostly.  ASSERT certainly provides *more* functionality.
There are also nice aspects to INSIST that ASSERT misses on, though
not enough to make me prefer INSIST overall, now that I've learned
about ASSERT -- on those occasions where something of that sort is
desirable at all.  (There was really no need for either in the code I
posted, it was just a relic of that moment when I had INSIST in my
head.)  And in any case, sticking to something that's already standard
in the language is in general a winner, right?

  ba> This macro is all over the place in Schank & Riesbeck's "Inside
  ba> Case Based Reasoning" so I assume that's how it migrated to
  ba> UChicago (via Hammond & others).

Ja... Und?

While we're on the subject, I also noticed too late (*sigh*) that
there was another non-standard macro, FOR, in the SYMCAT code I
posted.  Sorry, everybody.  It could easily be replaced by a standard
mapping or iteration construct.

--
Mitch Marks    ········@cs.UChicago.EDU
"Oh God comma I abhor self-consciousness" --John Barth