From: Jamie Zawinski
Subject: Re: explode macro/function for SUN cl
Date: 
Message-ID: <4257@pt.cs.cmu.edu>
Jerry B. Altzman writes:
> Does anyone out there have an explode macro or function?

I would say that if you want to use EXPLODE/IMPLODE, then you're almost
certainly not taking advantage of the language.  This is what strings
are for; EXPLODE/IMPLODE are leftovers from early Lisps which did not 
have strings.  Say you want to get the first character of a symbol - you
could do this with
	(char (symbol-name symbol) 0)
or with
	(car (explode symbol))

The former will return a character object, which is likely stored as an
immediate quantity.  The latter will return a pointer to a symbol,
which is a data structure of five slots, including a string of its
name; also, symbols are entered in a package hash table, which adds
some more overhead.

EXPLODE could be implemented as

(defun explode (sym)
  (let ((list '())
        (string (symbol-name sym)))
    (dotimes (i (length string))
      (push (intern (string (char string i))) list))
    (nreverse list)))

This means that INTERN will be called for every element of the
namestring of the symbol, which will do a hash-table-store.
Also, INTERN must be called with a string, so a number of one-character
strings are created as well.  Finally, a list is consed.
So it's a real lose; anything else would be more efficient.

Read the chapter of "Common Lisp: the Language" on sequence functions;
there are a plethora of functions that operate on strings and arrays as
well as lists.

Jamie Zawinski
···@spice.cs.cmu.edu
sun!sunpitt!eti!jwz
-- 

From: Barry Margolin
Subject: Re: explode macro/function for SUN cl
Date: 
Message-ID: <36368@think.UUCP>
In article <····@pt.cs.cmu.edu> ···@spice.cs.cmu.edu (Jamie Zawinski) writes:
>EXPLODE could be implemented as
[code deleted]
>This means that INTERN will be called for every element of the
>namestring of the symbol, which will do a hash-table-store.

While I agree with everything else you said, I have one question: why
are you INTERNing the symbols?  For the purposes of EXPLODE and
IMPLODE, uninterned symbols should probably work.  Actually, it really
depends on how the caller plans on using the list.

I suspect that the requester knows that this is not the right way to
do what he's doing.  My guess is he's trying to port some old Franz
Lisp code to Common Lisp, and it makes use of EXPLODE.

By the way, the function requested (and which you implemented) is
closer to MacLisp's EXPLODEC than EXPLODE.  EXPLODE in MacLisp returns
a list of the characters making up the object's printed
representation.  It works on any object, and it includes the slashes.
It could be defined as:

(defun explode (object &optional (intern-p t))
  (let ((string (prin1-to-string object))
	(result nil)
	(one-char-string (make-string 1)))
    (map 'list #'(lambda (char)
		   (setf (char one-char-string 0) char)
		   (if intern-p
		       (intern one-char-string)
		       (make-symbol one-char-string))))))

I added the INTERN-P optional argument to allow interning to be
disabled.  MacLisp EXPLODEC would be the same, except PRIN1-TO-STRING
would be replaced with PRINC-TO-STRING.

Note also the reuse of ONE-CHAR-STRING in my definition.  I think this
is about as efficient as one can get using only standard Common Lisp.
Unfortunately there is still the string containing the printed
representation; if Common Lisp had a way to define streams, you could
implement a stream that took the characters and collected them into a
immediately.


Barry Margolin
Thinking Machines Corp.

······@think.com
{uunet,harvard}!think!barmar
From: Skef Wholey
Subject: Re: explode macro/function for SUN cl
Date: 
Message-ID: <4271@pt.cs.cmu.edu>
Both ···@spice.cs.cmu.edu and ······@think.com present versions of
EXPLODE, with the well-meaning and correct advice that such awful
functions be used only for compatibility with smelly old code you don't
want to crawl around inside of.

However, neither of them comes up with a very efficient implementation
of EXPLODE.  Come on, guys!  I've seen you code, I know you can do
better than this!  Here's the trick: keep a table that maps character
codes to symbols, and index into that.  No need to call either INTERN or
MAKE-SYMBOL for every character in the explodee.

For efficiently exploding symbols, this code will do the trick:

    ;;; -*- Mode: Lisp; Package: EXPLODE -*-
    ;;;
    (in-package "EXPLODE")

    (defvar *explode-package* (find-package "EXPLODE"))

    (defvar *explode-initialized* nil)

    (defvar *char-code-to-symbols* (make-array char-code-limit))

    (defun explode (symbol)
      ;; First time we're called, fill up the table:
      (unless *explode-initialized*
	(dotimes (i char-code-limit)
	  (setf (aref *char-code-to-symbols* i)
		(intern (string (code-char i)) *explode-package*)))
	(setq *explode-initialized* t))
      (do ((i 0 (1+ i))
	   (list nil)
	   (name (symbol-name symbol)))
	  ((= i (length name))
	   (nreverse list))
	(push (aref *char-code-to-symbols* (char-code (char name i))) list)))

Yeah, I know, consing up the list backwards and NREVERSE'ing it is not
awesomely elegant, but, hey, it worked the first time:

    * (compile-file "explode.lisp" :load t)

    Error output from /usr1/skef/explode.lisp 13-Feb-89 22:11:25.
    Compiled on 13-Feb-89 22:11:53 by CLC version M1.7 (8-Feb-89).

    EXPLODE compiled.

    Finished compilation of file "/usr1/skef/explode.lisp".
    0 Errors, 0 Warnings.
    Elapsed time 0:00:08, run time 0:00:01.

    T
    * (in-package "EXPLODE")
    #<The EXPLODE package, 253/390 internal, 0/9 external>
    * (explode 'foobar)
    (F O O B A R)
    * (explode 'foobar-bazola)
    (F O O B A R - B A Z O L A)
    * (explode 'yow!)
    (Y O W !)

To work on numbers and other weird things, SYMBOL-NAME can be replaced
with PRIN1-TO-STRING or PRINC-TO-STRING...
--