From: Daniel Leidisch
Subject: generic to-string function
Date: 
Message-ID: <f1qore$fak$03$1@news.t-online.com>
Hello!

I've just read the PCL chapters about CLOS and since I find
it a bit annoying that ther is no unified way of converting
different objects into strings, I gave it a try:

(defgeneric to-string (item)
  (:documentation "Returns item as a string.")
  (:method ((item string))
    item)
  (:method ((item character))
    (string item))
  (:method ((item symbol))
    (string item))
  (:method ((item number))
    (write-to-string item))
  (:method ((item sequence))
    (if (every #'characterp item)
        (coerce item 'string)
        (error "Sequence item contains non-characters."))))

Personally, I think it's quite convenient and I have put it
in my toolbox.lisp, along with some other stuff (most of it
shamelessly copied from cll or other resources).

Being quite new to Lisp (I've just worked through Touretzky's
Gentle Introduction and read a bit of On Lisp (dropped it
in favor of PCL), right now I'm starting Chapter 19 of PCL),
I wondered how experienced Lispers think of it.

1. Is it a good thing to do, or should I drop it?
2. If it's a good thing, could (should?) it be done better?

From: D Herring
Subject: Re: generic to-string function
Date: 
Message-ID: <aO6dnYfMIKZ0d93bnZ2dnUVZ_ruknZ2d@comcast.com>
Daniel Leidisch wrote:
> I've just read the PCL chapters about CLOS and since I find
> it a bit annoying that there is no unified way of converting
> different objects into strings, I gave it a try:

A good first try, but there is a standard framework to do this.

(format nil "~A" item)
or
(format nil "~S" item)

Does the job for most things.

To extend this system, take a look at
http://www.lisp.org/HyperSpec/Body/chap-22.html
and especially
http://www.lisp.org/HyperSpec/Body/sec_22-1-3.html
http://www.lisp.org/HyperSpec/Body/stagenfun_print-object.html

- Daniel
From: Daniel Leidisch
Subject: Re: generic to-string function
Date: 
Message-ID: <f1qr78$66q$00$1@news.t-online.com>
Thus spoke D Herring <········@at.tentpost.dot.com>:
...
> A good first try, but there is a standard framework to do this.
> 
> (format nil "~A" item)
> or
> (format nil "~S" item)
...

I just don't know why I didn't think of format -- actually I've used
it quite a few times, but only for printing to the screen. Sometimes
the easiest solutions don't come to ones mind.

Thanks!

dhl
From: Holger Schauer
Subject: Re: generic to-string function
Date: 
Message-ID: <yxzy7jx6ig5.fsf@gmx.de>
On 4997 September 1993, Daniel Leidisch wrote:
> Thus spoke D Herring <········@at.tentpost.dot.com>:
>> A good first try, but there is a standard framework to do this.
> I just don't know why I didn't think of format -- actually I've used
> it quite a few times, but only for printing to the screen. Sometimes
> the easiest solutions don't come to ones mind.

Having used Perl a lot recently, I wondered how to simulate join in
CL. That's actually so simple, I'll probably never going to use the
following function ever:

(defun string-join (sep sequence)
  (format nil (concatenate 'string 
			   "~{~A~^" 
			   (or (and (typep sep 'sequence)
				    sep)
			       (list sep)) 
			   "~}")
	  sequence))

CL-USER> (string-join ";" (list 'a 'b 'c))
"A;B;C"

The ugliness therein is solely due to the necessary embedding of the
seperator. Without it (i.e. you don't the generality of a variable
separator because yo know which one you want), it simply boils down to

CL-USER> (format nil "~{~A~^;~}" (list 'a 'b 'c))
"A;B;C"

Holger

-- 
---          http://hillview.bugwriter.net/            ---
Fachbegriffe der Informatik - Einfach erkl�rt
190: Cisco
       Protokolhure. (unbekannt)
From: Kent M Pitman
Subject: Re: generic to-string function
Date: 
Message-ID: <u8xbwx299.fsf@nhplace.com>
Holger Schauer <··············@gmx.de> writes:

> The ugliness therein is solely due to the necessary embedding of the
> seperator. Without it (i.e. you don't the generality of a variable
> separator because yo know which one you want), it simply boils down to

Make sure to protect sep against cntaining a "~" when you edit the format
string.  You can map through the thing trying to repair tildes, but it's
easier to do something like:

 (defun xstring-join (list &optional (sep #\Space))
   (format nil "~:{~A~:^~A~}" 
           (mapcar #'(lambda (elt) (list elt sep)) list)))

(I didn't test this.  But I think the concept is right.  Hope it helps.)

(Btw, I use the convention of a prefix "X" to mean args are exchanged.
 Origin: Maclisp had an XCONS that took its args in reverse order,
 (xcons kdr kar), which was occasionally handy.   I like the the
 separator second since it should be omittable.)
From: Holger Schauer
Subject: Re: generic to-string function
Date: 
Message-ID: <yxzvef07hw7.fsf@gmx.de>
On 4999 September 1993, Kent M. Pitman wrote:
> Holger Schauer <··············@gmx.de> writes:
>> The ugliness therein is solely due to the necessary embedding of the
>> seperator. Without it (i.e. you don't the generality of a variable
>> separator because yo know which one you want), it simply boils down to
>
> Make sure to protect sep against cntaining a "~" when you edit the format
> string.   [...]

Thanks. But the main point I wanted to make wasn't really about that
string-join function, but rather about the abilities of format. 

Fiddling with it was merely a nice excuse for looking again at formats
more complex capabilities for me. As soon as I noted that the task was
so easy to solve with format directly and that format is applicable to
a much wider domain, the very idea of some string-join function looked
rather silly to me.

>  I like the the separator second since it should be omittable.

Perl has it the other way round, because the list argument may have
arbitrary length. So even closer to perl would have been:

(defun string-join (sep expr &rest rest)  ...)

This is probably because Perl doesn't have a general sequence type, so
in CL one can indeed easily trade that unnecessary rest argument for an
omittable separator.

Holger

-- 
---          http://hillview.bugwriter.net/            ---
"I mean, the bazaar I don't mind, but the bizarre I have problems with."
                  -- Russell Marks in comp.os.linux.announce
From: Pascal Bourguignon
Subject: Re: generic to-string function
Date: 
Message-ID: <876470n68q.fsf@thalassa.lan.informatimago.com>
Holger Schauer <··············@gmx.de> writes:

> On 4997 September 1993, Daniel Leidisch wrote:
>> Thus spoke D Herring <········@at.tentpost.dot.com>:
>>> A good first try, but there is a standard framework to do this.
>> I just don't know why I didn't think of format -- actually I've used
>> it quite a few times, but only for printing to the screen. Sometimes
>> the easiest solutions don't come to ones mind.
>
> Having used Perl a lot recently, I wondered how to simulate join in
> CL. That's actually so simple, I'll probably never going to use the
> following function ever:
>
> (defun string-join (sep sequence)
>   (format nil (concatenate 'string 
> 			   "~{~A~^" 
> 			   (or (and (typep sep 'sequence)
> 				    sep)
> 			       (list sep)) 
> 			   "~}")
> 	  sequence))

Ugh!  (if (typep sep 'sequence) 
          sep
          (list sep))


But otherwise, either use Ken's solution or:

(defun string-join (sequence &optional (sep #\space))
  (format nil (format nil "~~{~~A~~^~A~~}" sep) sequence))


C/USER[4]> (string-join '(abc 1 "abc" (a b c) #(a b c))
                        #(- even a vector can separate -))
"ABC#(- EVEN A VECTOR CAN SEPARATE -)1#(- EVEN A VECTOR CAN SEPARATE -)abc#(- EVEN A VECTOR CAN SEPARATE -)(A B C)#(- EVEN A VECTOR CAN SEPARATE -)#(A B C)"
C/USER[5]> (string-join '(abc 1 "abc" (a b c) #(a b c)) )
"ABC 1 abc (A B C) #(A B C)"
C/USER[6]> (string-join '(abc 1 "abc" (a b c) #(a b c)) "|")
"ABC|1|abc|(A B C)|#(A B C)"
C/USER[7]> (string-join '(a b c) ";")
"A;B;C"

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
        Un chat errant
se soulage
        dans le jardin d'hiver
                                        Shiki
From: Kent M Pitman
Subject: Re: generic to-string function
Date: 
Message-ID: <u4pmkwsw7.fsf@nhplace.com>
Pascal Bourguignon <···@informatimago.com> writes:

> But otherwise, either use Ken's solution or:
> 
> (defun string-join (sequence &optional (sep #\space))
>   (format nil (format nil "~~{~~A~~^~A~~}" sep) sequence))

This also has the tilde quoting problem.  You have to always worry about
that when you're making up format strings.

  (string-join "foo" "~")
  Error: Terminator #\} not found in "~{~A~^~~}".

If you do this a lot, you'll want to make a quote-for-format operation.
Otherwise, you're better off to arrange for the separator to be data, 
not format string.
From: Pascal Bourguignon
Subject: Re: generic to-string function
Date: 
Message-ID: <87fy64lj6l.fsf@thalassa.lan.informatimago.com>
Kent M Pitman <······@nhplace.com> writes:

> Pascal Bourguignon <···@informatimago.com> writes:
>
>> But otherwise, either use Ken's solution or:
s/Ken/Kent/ ; sorry.
 
>> (defun string-join (sequence &optional (sep #\space))
>>   (format nil (format nil "~~{~~A~~^~A~~}" sep) sequence))
>
> This also has the tilde quoting problem.  You have to always worry about
> that when you're making up format strings.
>
>   (string-join "foo" "~")
>   Error: Terminator #\} not found in "~{~A~^~~}".
>
> If you do this a lot, you'll want to make a quote-for-format operation.
> Otherwise, you're better off to arrange for the separator to be data, 
> not format string.

Yes, that's right.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

WARNING: This product attracts every other piece of matter in the
universe, including the products of other manufacturers, with a
force proportional to the product of the masses and inversely
proportional to the distance between them.
From: Alan Crowe
Subject: Re: generic to-string function
Date: 
Message-ID: <86ejlofzfv.fsf@cawtech.freeserve.co.uk>
Daniel Leidisch <····@leidisch.net> writes:

> Hello!
> 
> I've just read the PCL chapters about CLOS and since I find
> it a bit annoying that ther is no unified way of converting
> different objects into strings, I gave it a try:
> 

http://www.lisp.org/HyperSpec/Body/fun_write-to-_nc-to-string.html

write-to-string, prin1-to-string, and princ-to-string are
used to create a string consisting of the printed
representation of object. Object is effectively printed as
if by write, prin1, or princ, respectively, and the
characters that would be output are made into a string.
From: Daniel Leidisch
Subject: Re: generic to-string function
Date: 
Message-ID: <f1voh3$kb2$00$1@news.t-online.com>
Thus spoke Alan Crowe <····@cawtech.freeserve.co.uk>:
> http://www.lisp.org/HyperSpec/Body/fun_write-to-_nc-to-string.html
> 
> write-to-string, prin1-to-string, and princ-to-string are
> used to create a string consisting of the printed
> representation of object. Object is effectively printed as
> if by write, prin1, or princ, respectively, and the
> characters that would be output are made into a string.

Thanks for pointing this out, princ-to-string is what I was looking
for. I'll use it instead of format's "aesthetic" directive, when
there is no need for format's other features.

dhl