Hello
I'm trying to write something like this:
(case-preserving-context
(a list of symbols))
=>
(|a| |list| |of| |symbols|)
I've read chapter 2 and chapter 23 of CLHS, and managed to get something
like:
#$(a list of symbols)
=>
(|a| |list| |of| |symbols|)
Which basically setf the readtable-case of *readtable* to :preserve then
funcalls the function associated with backquote. It does the trick, but I'd
like something cleaner, if possible. Some suggestions?
Thanks in advance
--
+-----------------
| Francisco Vides Fernández <······@dedaloingenieros.com>
| Director técnico.
| Dédalo Ingenieros http://www.dedaloingenieros.com/
| PGP: http://pgp.rediris.es:11371/pks/lookup?op=index&search=0xB1299C15
+------
From: Pascal J. Bourguignon
Subject: Re: reading symbols preserving case
Date:
Message-ID: <87skks6n1c.fsf@galatea.local>
Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com> writes:
> Hello
>
> I'm trying to write something like this:
>
> (case-preserving-context
> (a list of symbols))
> =>
> (|a| |list| |of| |symbols|)
>
> I've read chapter 2 and chapter 23 of CLHS, and managed to get something
> like:
>
> #$(a list of symbols)
> =>
> (|a| |list| |of| |symbols|)
>
> Which basically setf the readtable-case of *readtable* to :preserve then
> funcalls the function associated with backquote. It does the trick, but I'd
> like something cleaner, if possible. Some suggestions?
Why do you want to quote it? There's a QUOTE special operator
perfectly good for quoting things.
(defun preserve-case-dispatching-reader-macro (stream sub-char arg)
(declare (ignore sub-char arg))
(let ((*readtable* (copy-readtable *readtable*)))
(setf (readtable-case *readtable*) :preserve)
(read stream)))
C/USER[59]> (set-dispatch-macro-character #\# #\$ (lambda (&rest args) (apply 'PRESERVE-CASE-DISPATCHING-READER-MACRO args)))
T
C/USER[50]> '#$(a list of symbols)
(|a| |list| |of| |symbols|)
C/USER[51]> #$(PROGN (PRINT '(a list of symbols)) (VALUES))
(|a| |list| |of| |symbols|)
C/USER[52]>
--
__Pascal Bourguignon__
Pascal J. Bourguignon wrote:
> Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com>
> writes:
>
>> Which basically setf the readtable-case of *readtable* to :preserve then
>> funcalls the function associated with backquote. It does the trick, but
>> I'd like something cleaner, if possible. Some suggestions?
>
> Why do you want to quote it? There's a QUOTE special operator
> perfectly good for quoting things.
Is not QUOTE, but QUASIQUOTE, and it is because I want to do something like
(let ((foo "bar"))
#$(baz ,foo bla))
=>
(|baz| "bar" |bla|)
> (defun preserve-case-dispatching-reader-macro (stream sub-char arg)
> (declare (ignore sub-char arg))
> (let ((*readtable* (copy-readtable *readtable*)))
> (setf (readtable-case *readtable*) :preserve)
> (read stream)))
Your code is far more concise an clean than the one I'm writing, but does
more or less the same.
My question is: can I do this whithout prepending #$ ? It works fine the way
you did it, but I'd like to know if can be done.
--
+-----------------
| Francisco Vides Fernández <······@dedaloingenieros.com>
| Director técnico.
| Dédalo Ingenieros http://www.dedaloingenieros.com/
| PGP: http://pgp.rediris.es:11371/pks/lookup?op=index&search=0xB1299C15
+------
Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com> writes:
> Pascal J. Bourguignon wrote:
> > (defun preserve-case-dispatching-reader-macro (stream sub-char arg)
> > (declare (ignore sub-char arg))
> > (let ((*readtable* (copy-readtable *readtable*)))
> > (setf (readtable-case *readtable*) :preserve)
> > (read stream)))
>
> Your code is far more concise an clean than the one I'm writing, but does
> more or less the same.
>
> My question is: can I do this whithout prepending #$ ? It works fine the way
> you did it, but I'd like to know if can be done.
As a short answer: No. You need the #$ or something similar.
This is related to another thread here concerning the different times
that are associated with reading and evaluating lisp forms. The
creation or finding of symbols is done at READ-TIME, so you have to
arrange for the proper setting of READTABLE-CASE at read time. So that
forces you to use a reader macro of some sort.
You could, presumably use a different flavor of reader macro, for
example using {...} or [...] to do the reading of delimited input with
appropriate syntax set. Those characters are reserved by the standard
for end-user applications. But then you have to have a full list form.
The advantage of Pascal's solution is that it will work on individual
symbols as well:
#$fooBar => |fooBar|
If you want to have backquoted lists, you just have to backquote the
form that follows the #$:
(let ((with "with")
(spliced 'spliced))
#$`(a list ,WITH ,SPLICED elements))
--
Thomas A. Russ, USC/Information Sciences Institute
In article <·······················@giganews.com>,
Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com>
wrote:
> Pascal J. Bourguignon wrote:
>
> > Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com>
> > writes:
> >
>
> >> Which basically setf the readtable-case of *readtable* to :preserve then
> >> funcalls the function associated with backquote. It does the trick, but
> >> I'd like something cleaner, if possible. Some suggestions?
> >
> > Why do you want to quote it? There's a QUOTE special operator
> > perfectly good for quoting things.
>
> Is not QUOTE, but QUASIQUOTE, and it is because I want to do something like
>
> (let ((foo "bar"))
> #$(baz ,foo bla))
> =>
> (|baz| "bar" |bla|)
I think you'll actually have to write:
(let ((foo "bar"))
#$(baz ,FOO bla))
because within #$, foo will be read as |foo|, but the variable you bound
was FOO.
>
> > (defun preserve-case-dispatching-reader-macro (stream sub-char arg)
> > (declare (ignore sub-char arg))
> > (let ((*readtable* (copy-readtable *readtable*)))
> > (setf (readtable-case *readtable*) :preserve)
> > (read stream)))
>
> Your code is far more concise an clean than the one I'm writing, but does
> more or less the same.
>
> My question is: can I do this whithout prepending #$ ? It works fine the way
> you did it, but I'd like to know if can be done.
You certainly can't do it with an ordinary macro, as your initial
example showed. Case mapping is done by the reader, and the entire
expression is read before the macro is invoked. So you need something
that operates at the reader level, and that's what read macros do.
--
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
On 1 abr, 19:57, Barry Margolin <······@alum.mit.edu> wrote:
> In article <·······················@giganews.com>,
> Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com>
>
>
>
> wrote:
> > Pascal J. Bourguignon wrote:
>
> > > Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com>
> > > writes:
>
> > >> Which basically setf the readtable-case of *readtable* to :preserve then
> > >> funcalls the function associated with backquote. It does the trick, but
> > >> I'd like something cleaner, if possible. Some suggestions?
>
> > > Why do you want to quote it? There's a QUOTE special operator
> > > perfectly good for quoting things.
>
> > Is not QUOTE, but QUASIQUOTE, and it is because I want to do something like
>
> > (let ((foo "bar"))
> > #$(baz ,foo bla))
> > =>
> > (|baz| "bar" |bla|)
>
> I think you'll actually have to write:
>
> (let ((foo "bar"))
> #$(baz ,FOO bla))
>
> because within #$, foo will be read as |foo|, but the variable you bound
> was FOO.
>
Not necessarily. The read macro can invoke the "default" reader
whenever it finds a comma. And, according to what he is saying, this
is probably what he is going to do.
But this is going to be the case if he uses your suggestion below.
Maybe he can adapt your suggestion?
>
>
> > > (defun preserve-case-dispatching-reader-macro (stream sub-char arg)
> > > (declare (ignore sub-char arg))
> > > (let ((*readtable* (copy-readtable *readtable*)))
> > > (setf (readtable-case *readtable*) :preserve)
> > > (read stream)))
>
> > Your code is far more concise an clean than the one I'm writing, but does
> > more or less the same.
>
> > My question is: can I do this whithout prepending #$ ? It works fine the way
> > you did it, but I'd like to know if can be done.
>
> You certainly can't do it with an ordinary macro, as your initial
> example showed. Case mapping is done by the reader, and the entire
> expression is read before the macro is invoked. So you need something
> that operates at the reader level, and that's what read macros do.
>
> --
> Barry Margolin, ······@alum.mit.edu
> Arlington, MA
> *** PLEASE post questions in newsgroups, not directly to me ***
> *** PLEASE don't copy me on replies, I'll read them in the group ***
gugamilare wrote:
>> I think you'll actually have to write:
>>
>> (let ((foo "bar"))
>> #$(baz ,FOO bla))
>>
>> because within #$, foo will be read as |foo|, but the variable you bound
>> was FOO.
>>
> Not necessarily. The read macro can invoke the "default" reader
> whenever it finds a comma. And, according to what he is saying, this
> is probably what he is going to do.
>
> But this is going to be the case if he uses your suggestion below.
> Maybe he can adapt your suggestion?
In fact I already implemented comma that way, preserving the default reader
table case.
--
+-----------------
| Francisco Vides Fernández <······@dedaloingenieros.com>
| Director técnico.
| Dédalo Ingenieros http://www.dedaloingenieros.com/
| PGP: http://pgp.rediris.es:11371/pks/lookup?op=index&search=0xB1299C15
+------
From: Pascal J. Bourguignon
Subject: Re: reading symbols preserving case
Date:
Message-ID: <87fxgs6liv.fsf@galatea.local>
Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com> writes:
> Pascal J. Bourguignon wrote:
>
>> Francisco Vides =??B?RmVybsOhbmRleg==?= <······@dedaloingenieros.com>
>> writes:
>>
>
>>> Which basically setf the readtable-case of *readtable* to :preserve then
>>> funcalls the function associated with backquote. It does the trick, but
>>> I'd like something cleaner, if possible. Some suggestions?
>>
>> Why do you want to quote it? There's a QUOTE special operator
>> perfectly good for quoting things.
>
> Is not QUOTE, but QUASIQUOTE, and it is because I want to do something like
>
> (let ((foo "bar"))
> #$(baz ,foo bla))
> =>
> (|baz| "bar" |bla|)
>
>> (defun preserve-case-dispatching-reader-macro (stream sub-char arg)
>> (declare (ignore sub-char arg))
>> (let ((*readtable* (copy-readtable *readtable*)))
>> (setf (readtable-case *readtable*) :preserve)
>> (read stream)))
>
> Your code is far more concise an clean than the one I'm writing, but does
> more or less the same.
>
> My question is: can I do this whithout prepending #$ ? It works fine the way
> you did it, but I'd like to know if can be done.
You may set the readtable case to preserve globally. Just get the
habit of typing in uppercase by default.
C/USER[67]> (setf (readtable-case *readtable*) :preserve)
:PRESERVE
C/USER[68]> (LET ((FOO "bar"))
`(baz ,FOO bla))
(baz "bar" bla)
C/USER[69]> (DOTIMES (I 3) (PRINT `(Baz ,I quux bla)))
(Baz 0 quux bla)
(Baz 1 quux bla)
(Baz 2 quux bla)
NIL
--
__Pascal Bourguignon__
Francisco Vides Fernández <······@dedaloingenieros.com> wrote:
+---------------
| I'm trying to write something like this:
| (case-preserving-context
| (a list of symbols))
| =>
| (|a| |list| |of| |symbols|)
...
| Which basically setf the readtable-case of *readtable* to :preserve ...
| but I'd like something cleaner, if possible. Some suggestions?
+---------------
Others have given you good answers, but depending on exactly what
you're trying to accomplish, you might want to take a close look
at :INVERT rather than :PRESERVE. Assuming your source code is all
lowercase, you can (setf (readtable-case *readtable*) :invert) and
*leave* it that way, and still preserve CamelCase:
> (readtable-case *readtable*)
:UPCASE
> 'foo
FOO
> (setf (readtable-case *readtable*) :invert)
:invert
> 'foo
foo
> '(A List Of Symbols such as FOO & BAR)
(A List Of Symbols such as FOO & BAR)
> (mapcar #'symbol-name *) ; Show the "real" internal case
("a" "List" "Of" "Symbols" "SUCH" "AS" "foo" "&" "bar")
> (eq 'foo (intern "FOO")) ; So lowercase source code works
t
> (eq 'FOO (intern "FOO")) ; but uppercase source doesn't,
nil
> (eq 'FOO (intern "foo")) ; unless you really do want lowercase names.
t
>
When readtable-case is :INVERT, the printer also inverts on output
by default. If all you need is read/print invariance of case, :INVERT
may be your friend.
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Rob Warnock wrote:
> When readtable-case is :INVERT, the printer also inverts on output
> by default. If all you need is read/print invariance of case, :INVERT
> may be your friend.
:-(rant
Invert was a horrible (though elegant) hack which needs to die. CL
should not be held back by the few people WHO STILL PREFER WRITING IN
ALL CAPS. Its something that rarely makes sense in most character
sets outside of ASCII a-zA-Z.
(+ 1 2 x) -> (= ! @ X) ?!?
Its not terribly hard to recompile the core with lowercase names. Its
not terribly hard to set :invert before reading legacy lisp files. It
is terribly hard to convince non-CL-fans that an inverting reader is
sane in today's language ecosystem.
In a case-insensitive world, it doesn't matter. In a case-preserving
world, case-inversion is a backwards waste of CPU cycles.
:-)
- Daniel
D Herring <········@at.tentpost.dot.com> writes:
> Rob Warnock wrote:
>
> > When readtable-case is :INVERT, the printer also inverts on output
> > by default. If all you need is read/print invariance of case, :INVERT
> > may be your friend.
>
> :-(rant
>
> Invert was a horrible (though elegant) hack which needs to die. CL
> should not be held back by the few people WHO STILL PREFER WRITING IN
> ALL CAPS. Its something that rarely makes sense in most character sets
> outside of ASCII a-zA-Z.
>
> (+ 1 2 x) -> (= ! @ X) ?!?
>
> Its not terribly hard to recompile the core with lowercase names. Its
> not terribly hard to set :invert before reading legacy lisp files. It
> is terribly hard to convince non-CL-fans that an inverting reader is
> sane in today's language ecosystem.
>
> In a case-insensitive world, it doesn't matter. In a case-preserving
> world, case-inversion is a backwards waste of CPU cycles.
Well to rant back:
I think the real answer is to have all of these features:
lower-case built-in names
case-preserving reader
case-insensitive symbol name comparisons
That seems to be the behavior of the file systems on Windows and
Macintosh OSes.
It really doesn't make a lot of sense to support foo-bar Foo-Bar and
Foo-bar as three different symbols. Most non-programmers don't really
consider them different.
So the symbol behavior should be case-preserving AND case-insensitive.
--
Thomas A. Russ, USC/Information Sciences Institute
On Apr 3, 6:21 pm, ····@sevak.isi.edu (Thomas A. Russ) wrote:
> It really doesn't make a lot of sense to support foo-bar Foo-Bar and
> Foo-bar as three different symbols. Most non-programmers don't really
> consider them different.
>
> So the symbol behavior should be case-preserving AND case-insensitive.
I agree, but you'd be surprised how many programmers *want* case
sensitive symbol comparison. Qi has case sensitive symbol comparison
for example. Go figure.
Raffael Cavallaro <················@gmail.com> wrote:
+---------------
| ····@sevak.isi.edu (Thomas A. Russ) wrote:
| > It really doesn't make a lot of sense to support foo-bar Foo-Bar and
| > Foo-bar as three different symbols. �Most non-programmers don't really
| > consider them different.
| >
| > So the symbol behavior should be case-preserving AND case-insensitive.
|
| I agree, but you'd be surprised how many programmers *want* case
| sensitive symbol comparison. Qi has case sensitive symbol comparison
| for example. Go figure.
+---------------
For me, case-sensitive symbol comparison mainly arises when
reading/writing data formats originating outside the Common Lisp
context that are themselves case-sensitive, e.g., EDIF design
files (such as produced by the OrCAD schematic capture program),
which are basically just case-sensitive s-exprs that use CamelCase
symbols [*megabytes* of them!!]. For this application, READTABLE-CASE
:INVERT works very well, since mainly you just need read/write invariance.
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Thomas A. Russ wrote:
> Well to rant back:
>
> I think the real answer is to have all of these features:
> lower-case built-in names
> case-preserving reader
> case-insensitive symbol name comparisons
>
> That seems to be the behavior of the file systems on Windows and
> Macintosh OSes.
>
> It really doesn't make a lot of sense to support foo-bar Foo-Bar and
> Foo-bar as three different symbols. Most non-programmers don't really
> consider them different.
>
> So the symbol behavior should be case-preserving AND case-insensitive.
Exactly.
While the default still misses common idioms in other languages,
setting (*case-sensitive-interning* t) is preferable to setting
(readtable-case :invert) for examples like the following.
English: I sat during the SAT.
Math: For all x in X, there exists y in Y such that y=f(x).
Java/C++: CamelCase camelCase(args); camelCase.f();
Attaching *case-sensitive-interning* to the reader would create other
problems. If Jack wrote (+ x X) in a case-insensitive context, and
Jill defines both x and X in a case-sensitive context, then what
happens when the reader reads Jack's code? The solution is for
sensitivity to be defined at the package level (much as filename
sensitivity is fixed per filesystem).
Then I could
(defpackage "English" (:case-sensitive t) ...)
(defpackage "Math" (:case-sensitive t) ...)
(defpackage "Java/C++" (:case-sensitive t) ...)
and everyone would be happy.
(loop for math:x in math:X do ...)
Later,
Daniel
Rob Warnock wrote:
> When readtable-case is :INVERT, the printer also inverts on output
> by default. If all you need is read/print invariance of case, :INVERT
> may be your friend.
The problem I try to solve is the following: I'm trying to build a language
to portabily manage unix processes (or maybe processes in general). I've
used SCSH (http://www.scsh.net/) for some years, and now I'd like to have
something similar in CL.
This is my first serious project (I plan to use it heavily) after reading a
lot of CL books and lurking here for some time. I plan to release the code
as GPL when it's done.
The thing is: I'd like to write something like:
(let ((hi "hello world"))
(run/string (echo ,hi)))
=>
"hello world"
This is possible in SCSH because the original author, Olin Shivers, modified
the scheme reader (in fact SCSH isn't a fully compliant scheme because of
this). To do this, I need to read the process form preserving case because
this will be translated into a process invocation form (I'm designing it to
be portable among CL implementations)
After reading al answers to my original post, I think that the most
appropiate could be:
(let ((hi "hello world"))
#!(run/string (echo ,hi)))
=>
"hello world"
Because it will look like shebang header in unix scripts
+-----------------
| Francisco Vides Fernández <······@dedaloingenieros.com>
| Director técnico.
| Dédalo Ingenieros http://www.dedaloingenieros.com/
| PGP: http://pgp.rediris.es:11371/pks/lookup?op=index&search=0xB1299C15
+------
On Thu, 02 Apr 2009 23:47:59 +0200
Francisco Vides Fernández <······@dedaloingenieros.com> wrote:
> This is possible in SCSH because the original author, Olin Shivers,
> modified the scheme reader (in fact SCSH isn't a fully compliant
> scheme because of this).
Starting with R6RS the language is case-preserving anyway.
regards,
Marek
Marek Kubica <·····@xivilization.net> wrote:
+---------------
| Francisco Vides Fernández <······@dedaloingenieros.com> wrote:
| > This is possible in SCSH because the original author, Olin Shivers,
| > modified the scheme reader (in fact SCSH isn't a fully compliant
| > scheme because of this).
|
| Starting with R6RS the language is case-preserving anyway.
+---------------
I don't think Shivers had to modify the Scheme reader at all, since in
Scheme there is a *standard* mapping from the usual three "backquote"
readmacros to forms -- QUASIQUOTE, UNQUOTE, & UNQUOTE-SPLICING -- and
a "naked comma" is *NOT* illegal in Scheme's READ per se!
> (read)
,foo <=== I typed this.
(unquote foo)
> (read)
,@foo <=== I typed this.
(unquote-splicing foo)
> (read)
(let ((hi "hello world")) <=== I typed this.
(run/string (echo ,hi)))
(let ((hi "hello world")) (run/string (echo (unquote hi))))
>
Whereas in Common Lisp:
> (read)
,foo
Reader error at 13 on #<Two-Way Stream, Input = #<Synonym Stream to SYSTEM:*STDIN*>, Output = #<Synonym Stream to SYSTEM:*STDOUT*>>:
Comma not inside a backquote.
[Condition of type READER-ERROR]
...
...[enters debugger]...
That's why it's so hard to do a SCSH-like thing in CL.
[It can be done, but you have to tweak SCSH's RUN syntax a bit,
and the tweaks aren't portable because of the lack in CL of a
standard-required mapping from "`"/","/",@" to forms.]
-Rob
-----
Rob Warnock <····@rpw3.org>
627 26th Avenue <URL:http://rpw3.org/>
San Mateo, CA 94403 (650)572-2607
Rob Warnock wrote:
> Marek Kubica <·····@xivilization.net> wrote:
> +---------------
> | Francisco Vides Fernández <······@dedaloingenieros.com> wrote:
> | > This is possible in SCSH because the original author, Olin Shivers,
> | > modified the scheme reader (in fact SCSH isn't a fully compliant
> | > scheme because of this).
> |
> | Starting with R6RS the language is case-preserving anyway.
> +---------------
>
> I don't think Shivers had to modify the Scheme reader at all, since in
> Scheme there is a *standard* mapping from the usual three "backquote"
> readmacros to forms -- QUASIQUOTE, UNQUOTE, & UNQUOTE-SPLICING -- and
> a "naked comma" is *NOT* illegal in Scheme's READ per se!
He had to modify but not because of this. Here
http://www.scsh.net/docu/scsh-paper/scsh-paper-Z-H-9.html he details the
issues:
* symbol case preserving
* "+" and "-" to begin symbols
* "|" and "." as symbol constituents
* symbol begining with a digit
* #! as a comment read-macro
(BTW I still have to find which of these issues apply in CL)
> Whereas in Common Lisp:
>
> > (read)
> ,foo
> Reader error at 13 on #<Two-Way Stream, Input = #<Synonym Stream to
> SYSTEM:*STDIN*>, Output = #<Synonym Stream to SYSTEM:*STDOUT*>>:
Comma
> not inside a backquote.
> [Condition of type READER-ERROR]
> ...
> ...[enters debugger]...
>
> That's why it's so hard to do a SCSH-like thing in CL.
> [It can be done, but you have to tweak SCSH's RUN syntax a bit,
> and the tweaks aren't portable because of the lack in CL of a
> standard-required mapping from "`"/","/",@" to forms.]
I see. Well, this is going to be an interesting project :)
Thank you
--
+-----------------
| Francisco Vides Fernández <······@dedaloingenieros.com>
| Director técnico.
| Dédalo Ingenieros http://www.dedaloingenieros.com/
| PGP: http://pgp.rediris.es:11371/pks/lookup?op=index&search=0xB1299C15
+------