From: budden
Subject: A way to get rid of readmacros
Date: 
Message-ID: <09b3bab0-9508-445f-bc59-f77176d664cf@o6g2000yql.googlegroups.com>
This is no surprise that CL is ugly and, as usually, there
is an urgent need that I fix it. So here I am.

While doing read-eval we have no access to the stream
we read from. If we fix it, we can get rid of readmacros
or at least get a significant relief from that pain.

E.g., we can write
> '(hallo #.(preserve-case-1) Lisper)
and get
(HALLO |Lisper|)

Also we can write
> '(#.(in-package-1 :my-package) foo foo)
and get
'(my-package:foo foo)

http://paste.lisp.org/display/78029

Enjoy!

(in fact code is not tested well)
P.S. Don't forget to intern let1 into your cl package.

From: D Herring
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <49d7d7bd$0$3340$6e1ede2f@read.cnntp.org>
budden wrote:
> E.g., we can write
>> '(hallo #.(preserve-case-1) Lisper)
> and get
> (HALLO |Lisper|)

In this example, it would be easier to type |Lisper|...
For longer durations, see TCR's named readtables.
http://common-lisp.net/project/editor-hints/


> Also we can write
>> '(#.(in-package-1 :my-package) foo foo)
> and get
> '(my-package:foo foo)


I think my read-macros package solves this neatly
http://www.cliki.net/read-macros

Here's one of the examples:
;; lexical read manipulation
#?(read-let ((*read-base* 3)) 20) ; 6=2*3

So your examples would be
#?(read-let ((*package* (find-package :my-package))) foo foo)


- Daniel
From: budden
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <7e234e79-41db-4969-9966-55068e957cec@q16g2000yqg.googlegroups.com>
Hi Daniel!
  Rationale behind my design is that there
is only a narrow namespace for readmacros.
Moreover, CL suggests no way to resolve a
clash. Consider library X which defines #?
and your library which defines #? too. How
do I use both libraries together? There are
ugly workarounds to avoid the clash, but I
know no really good solution.
  Compare this to a way of resolving clashes
between symbols:

package1:symbol and package2:symbol

  There is also import and use-package
which allows to configure new package and choose
which symbol(s) I prefer to enter w/o qualifier.

  What I suggest is a way to alter reader's
behavior for the scope of one form w/o occupying
a single readmacro. Instead, I alter standard #.
sequence by exposing a stream being read to a user.
This seems to be a portable solution which allows to
use "readsymbols" instead of readmacros thus
allowing for really scalable syntax extensions.

#|
 Copyright (c) 2008 Daniel Herring
           (c) 2009 Budden
 Distributed under the Boost Software License, Version 1.0.
 Hope license part is ok ;)
|#
(defun here-document (delimiter)
  "\"#.(read-here delimiter) [text treated as a comments]
arbitrary text or (lisp expressions)
delimiter\"
Inspired by shell scripts (e.g. Bash).
Read lines from the current file until a line containing only
DELIMITER
\(with no leading or trailing whitespace) is found.  All lines before
that
point are then returned as a string.  No READ or EVAL is performed on
the
string. Due to REPL parser specifics of IDEs, be sure
to surround everything in a parens while using REPL. E.g.
\(progn #.(here-document \"EOL\")
Hallo world!
EOL
)
"
  (let* ((result nil)
         (delimiter (string delimiter)))
    (read-line *read-eval-stream* t nil t) ; ignore comments
    (do ((line (read-line *read-eval-stream* t nil t)
               (read-line *read-eval-stream* t nil t)))
        ((string= line delimiter))
      (push line result))
    (format nil "~{~A~#[~:;~%~]~}" (nreverse result))))

And sample usage (in REPL)
> (progn #.(here-document "EOL")
I'm not a lisper!
EOL
)
Progn is required here so that IDE
would not close input stream prematurely.
When written in file, progn is not needed and
you can write just

#.(here-document "EOL")
I'm not a lisper!
EOL
From: Raffael Cavallaro
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <873fb18c-3388-4a8b-aba0-7a178f94bdd6@e18g2000yqo.googlegroups.com>
On Apr 5, 5:46 am, budden <···········@mail.ru> wrote:

> Moreover, CL suggests no way to resolve a
> clash. Consider library X which defines #?
> and your library which defines #? too. How
> do I use both libraries together?

<http://common-lisp.net/~trittweiler/darcs/editor-hints/named-
readtables/>
From: budden
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <f79acbc3-9d07-416b-ba76-c9ed5bb9ac58@y7g2000yqa.googlegroups.com>
Thanks, I know about named-readtables.
I also know they are not portable.
From: Tobias C. Rittweiler
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <87fxfv46ri.fsf@freebits.de>
budden <···········@mail.ru> writes:

> Thanks, I know about named-readtables.
> I also know they are not portable.

Actually, I just pushed a portable implementation to the darcs
repository. I'll make a proper release the weeks comming.

  -T.
From: budden
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <6479f92e-c076-4367-a225-a2e4c2db3223@x31g2000prc.googlegroups.com>
> Actually, I just pushed a portable implementation to the darcs
> repository. I'll make a proper release the weeks comming.
That's nice
From: Madhu
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <m3ljpm52kp.fsf@moon.robolove.meer.net>
* "Tobias C. Rittweiler" <··············@freebits.de> :
Wrote on Sun, 26 Apr 2009 20:19:45 +0200:
|
|> Thanks, I know about named-readtables.
|> I also know they are not portable.
|
| Actually, I just pushed a portable implementation to the darcs
| repository. I'll make a proper release the weeks comming.

I was trying to understand what this involves --- I know you've been
talking about this for years, and think you wrote up a paper; I tried
searching for your writeup and did not find it, perhaps you could give a
pointer.

The named-readtables implemented by franz in allegro CL is very simple
there are two dictionary items NAMED-READTABLE and WITH-NAMED-READTABLE

<URL:http://www.franz.com/support/documentation/8.1/doc/operators/excl/named-readtable.htm>
<URL:http://www.franz.com/support/documentation/8.1/doc/operators/excl/with-named-readtable.htm>

When I have to use this in other lisps, the code is simply what it is
below

(defvar *named-readtables* nil
"Alist, each element is a cons whose key is a keyword representing 
a readtable name, and value is a readtable")

(defun named-readtable (name &optional errorp)
  (or (cdr (assoc (coerce name 'keyword) *named-readtables*))
      (and errorp (error "Readtable named ~S does not exist." name))))

(defsetf named-readtable (name) (store)
  (let ((name-var (gensym)) (store-var (gensym)))
    `(let* ((,name-var (coerce ,name 'keyword))
	    (,store-var ,store)
	    (cons (assoc ,name-var *named-readtables*)))
       (if cons
	   (rplacd cons ,store-var)
	   (prog1 ,store-var
	     (push (cons ,name-var ,store-var) *named-readtables*))))))

(defmacro with-named-readtable ((name) &body body)
  `(let ((cl:*readtable* (named-readtable ,name t))) ,@body))

There is also a requirement for a LIST-ALL-NAMED-READTABLES.  But
because it is really this simple, I cannot see what the fuss is about.
What am I missing?

--
Madhu
From: D Herring
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <49f5122c$0$29140$6e1ede2f@read.cnntp.org>
Madhu wrote:
> * "Tobias C. Rittweiler" <··············@freebits.de> :
> Wrote on Sun, 26 Apr 2009 20:19:45 +0200:
> |
> |> Thanks, I know about named-readtables.
> |> I also know they are not portable.
> |
> | Actually, I just pushed a portable implementation to the darcs
> | repository. I'll make a proper release the weeks comming.
> 
> I was trying to understand what this involves --- I know you've been
> talking about this for years, and think you wrote up a paper; I tried
> searching for your writeup and did not find it, perhaps you could give a
> pointer.
> 
> The named-readtables implemented by franz in allegro CL is very simple
> there are two dictionary items NAMED-READTABLE and WITH-NAMED-READTABLE
> 
> <URL:http://www.franz.com/support/documentation/8.1/doc/operators/excl/named-readtable.htm>
> <URL:http://www.franz.com/support/documentation/8.1/doc/operators/excl/with-named-readtable.htm>
> 
> When I have to use this in other lisps, the code is simply what it is
> below
...
> (defmacro with-named-readtable ((name) &body body)
>   `(let ((cl:*readtable* (named-readtable ,name t))) ,@body))

Who reads the body?

- Daniel
From: Madhu
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <m3hc0a4ze4.fsf@moon.robolove.meer.net>
* D Herring <·························@read.cnntp.org> :
Wrote on Sun, 26 Apr 2009 22:02:23 -0400:

|> (defmacro with-named-readtable ((name) &body body)
|>   `(let ((cl:*readtable* (named-readtable ,name t))) ,@body))
|
| Who reads the body?

I probably should be enlightened by considering that question, but I am
not.  The only claim made by the API is READTABLE is bound during the
execution of BODY. So the effect is that calls to the reader via READ in
BODY will be read with the named readtable.

[I'll have to see the alternative API before commenting on it or judging
 its value in the context of CL's "times".]

--
Madhu
From: Tobias C. Rittweiler
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <87ws96frdl.fsf@freebits.de>
Madhu <...> writes:

> * "Tobias C. Rittweiler" <··············@freebits.de> :
> Wrote on Sun, 26 Apr 2009 20:19:45 +0200:
> |
> |> Thanks, I know about named-readtables.
> |> I also know they are not portable.
> |
> | Actually, I just pushed a portable implementation to the darcs
> | repository. I'll make a proper release the weeks comming.
>
> I was trying to understand what this involves --- I know you've been
> talking about this for years, and think you wrote up a paper; 

I talked about it for a long time because I had no incentive to finish
it up properly; that changed recently. Everytime I worked on it I got
distracted, then lost interest again. It did not take so much time
because it was hard.


> I tried searching for your writeup and did not find it, perhaps you
> could give a pointer.

See below.


> The named-readtables implemented by franz in allegro CL is very simple
> there are two dictionary items NAMED-READTABLE and WITH-NAMED-READTABLE
>
> <URL:http://www.franz.com/support/documentation/8.1/doc/operators/excl/named-readtable.htm>
> <URL:http://www.franz.com/support/documentation/8.1/doc/operators/excl/with-named-readtable.htm>
>
> When I have to use this in other lisps, the code is simply what it is
> below
>
>   [...]

Yes that's it basically. With a bit more API around it, and some
different syntactic sugar.


> There is also a requirement for a LIST-ALL-NAMED-READTABLES.  But
> because it is really this simple, I cannot see what the fuss is about.
> What am I missing?

The fuss is about merging readtables. To do that you need to look into
the content of readtables, but as they're specified they're completely
opaque.

You can portably get all macro characters, and dispatch macro characters
by grovelling over every possible char, and poke with it at the
readtable. On Unicode-enabled Lisp implementations that are quite some
many characters to test for, though.

It works reasonably fast on SBCL, not so on CLISP. That is for the
standard readtable, you can make it arbitrarily crawl even on SBCL by
introducing arbitrarily many dispatch macro characters into the
readtable (for each you have to grovel once more.)


So I wanted to improve the situation and thought about a possible
extension for the ANSI standard. It's available here

  http://common-lisp.net/~trittweiler/with-readtable-iterator.pdf

And to actually make a difference in the implementations' landscape,
Ariel Badichi hacked it into Clisp, Stephen Compall into Clozure CL, and
I hacked it into SBCL.

This all looked good, but then I realized that the above is not enough
because readtables do not only describe macro characters but also
character syntax types. 

That's the reason why that writeup is still work-in-progress, and the
patches never made into the upstream versions. I have to redo the
proposal completely. 

And at that time I lost interest.

Now I think a first release does not have to be 100% perfect, especially
when the last few percents make up for perhaps 1% of the cases in
praxis. Best is the enemy of good &c &c.

So essentially it took so long because I really wanted to show you
something in MIT style of design, :-)

  -T.
From: budden
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <7de35b67-5370-4569-ba1c-2cad2dd579e8@y33g2000prg.googlegroups.com>
Hi Tobias!
 I took at your site, but it looks like I didn't find
a portable version.

 I think you could give up merging readtables. You could
just keep track of declared readmacros and merge named
readtables only. Also you could set things up so that
user would list characters he wants to import from other
readtable.
 E.g.

(defreadtable :second (:import-from :first (#\# #\;) $)
                      (:import-from :another #\[))

This seem to be much simpler to implement, with just
set-syntax-from-char, but still rather useful. Another
thing to incorporate is swank:*readtable-alist*

Also I think there should be just a global constant which keeps
a list of standard readmacros for a standard readtable.
From: Madhu
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <m3ab6248ek.fsf@moon.robolove.meer.net>
* "Tobias C. Rittweiler" <··············@freebits.de> :
Wrote on Mon, 27 Apr 2009 10:11:18 +0200:

[Re: named-readtables]

|> I was trying to understand what this involves --- I know you've been
|> talking about this for years, and think you wrote up a paper;
|
| I talked about it for a long time because I had no incentive to finish
| it up properly; that changed recently. Everytime I worked on it I got
| distracted, then lost interest again. It did not take so much time
| because it was hard.

But the problem you described of merging readtables below does indeed
seem hard.  More comments below:

|> I tried searching for your writeup and did not find it, perhaps you
|> could give a pointer.
| See below.

Thx

|> The named-readtables implemented by franz in allegro CL is very simple
|> there are two dictionary items NAMED-READTABLE and WITH-NAMED-READTABLE
|>
|> <URL:http://www.franz.com/support/documentation/8.1/doc/operators/excl/named-readtable.htm>
|> <URL:http://www.franz.com/support/documentation/8.1/doc/operators/excl/with-named-readtable.htm>

| Yes that's it basically. With a bit more API around it, and some
| different syntactic sugar.

[This simple API always seemed sound to me, I'd look at avoiding
 introducing an incompatible API.]

|> There is also a requirement for a LIST-ALL-NAMED-READTABLES.  But
|> because it is really this simple, I cannot see what the fuss is about.
|> What am I missing?
|
| The fuss is about merging readtables. To do that you need to look into
| the content of readtables, but as they're specified they're completely
| opaque.
|
| You can portably get all macro characters, and dispatch macro characters
| by grovelling over every possible char, and poke with it at the
| readtable. On Unicode-enabled Lisp implementations that are quite some
| many characters to test for, though.
|
| It works reasonably fast on SBCL, not so on CLISP. That is for the
| standard readtable, you can make it arbitrarily crawl even on SBCL by
| introducing arbitrarily many dispatch macro characters into the
| readtable (for each you have to grovel once more.)

CMUCL's unicode implementation went from using a huge array to keeping
an array + hashtable.  My gut says you will not be able to isolate
yourself from implementation dependent performance characterestics for
this task without unduly restricting the implementor.

I've never required automatic merging but perhaps another approach might
be possible if merging is absolutely required, heres the idea and the
motivation behind it:

Readtables always looked to me like keymaps in GNU Emacs or Xemacs.
They're anonymous opaque objects, and if you dont keep a reference to
them you can't get at them; [except in some dynamic context via
(current-global-map) and (current-local-map) in elisp]

Likewise one can imagine a local readtable and a global readtable (of
course 2 readtable contexts should be sufficient for anyone), and lookup
could be defined as looking up macro characters etc. in the given set of
active readtables in a given order.

This is of course a much bigger change.  But can you see any reasons for
not considering this instead?

--
Madhu
From: Tobias C. Rittweiler
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <87hc0afec1.fsf@freebits.de>
Madhu <...> writes:

> * "Tobias C. Rittweiler" <··············@freebits.de> :
> Wrote on Mon, 27 Apr 2009 10:11:18 +0200:
>
> [Re: named-readtables]
>
> |> The named-readtables implemented by franz in allegro CL is very simple
> |> there are two dictionary items NAMED-READTABLE and WITH-NAMED-READTABLE
> |> ...
> 
> | Yes that's it basically. With a bit more API around it, and some
> | different syntactic sugar.
>
> [This simple API always seemed sound to me, I'd look at avoiding
>  introducing an incompatible API.]

The implementation hooks into what Allegro provides so their (editor)
infrastructure will be reused smoothly. It also already integrates into
Slime, although not entirely properly (fsvo "properly".)

API wise I basically mirrored what's there for packages:

  DEFPACKAGE             -   DEFREADTABLE

  IN-PACKAGE             -   IN-READTABLE

  USE-PACKAGE            -   MERGE-READTABLES

  MAKE-PACKAGE           -   MAKE-READTABLE + REGISTER-READTABLE

  DELETE-PACKAGE         -   UNREGISTER-READTABLE

  RENAME-PACKAGE         -   RENAME-READTABLE

  FIND-PACKAGE           -   FIND-READTABLE

  PACKAGE-NAME           -   READTABLE-NAME

  LIST-ALL-PACKAGES      -   LIST-ALL-READTABLE-NAMES

[ WITH-PACKAGE-ITERATOR  -   WITH-READTABLE-ITERATOR ]
  
My goal was that any experienced Lisper will be able to take up the
package and know how to use it after glancing at it for one or two
minutes.

(One difference is that readtables are named by symbols not by string
designators. So TCR:SQL-SYNTAX and MADHU:SQL-SYNTAX can live next to
each other nicely.)


> This is of course a much bigger change.  But can you see any reasons for
> not considering this instead?

Yes, I did consider it. I'll reply to this later when I have more time.

  -T.
From: Tobias C. Rittweiler
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <87skjrxmco.fsf@freebits.de>
Madhu <·······@meer.net> writes:

> CMUCL's unicode implementation went from using a huge array to keeping
> an array + hashtable.  My gut says you will not be able to isolate
> yourself from implementation dependent performance characterestics for
> this task without unduly restricting the implementor.

I thought about wording it that implementators are encouraged (but not
formally required) to make the iteration not go through all available
characters---except when the user wants to iterate through all
constituent characters.

[The new interface of WITH-READTABLE-ITERATOR will look like
(with-readtable-iterator (iterator &rest syntax-types) &body body).]


> I've never required automatic merging but perhaps another approach might
> be possible if merging is absolutely required, ...

I wanted to mirror the package system as much as possible.

A package can :USE another package which is essentially run-time
inheritance. We can't do that with readtables. 

To make that work for readtables, there would have to exist a generic
function MACRO-CHAR-MISSING (in spirit of SLOT-MISSING, or
NO-APPLICABLE-METHOD) which you could use as a hook to implement such
inheritance at runtime. 

(Which would subsume your global / local readtable scheme, right?)

I decided that would be too much a change, in particular because you
can't easily shoehorn such a change into an implementation
retrospectively---contrarily to readtable iterators[*].

Hence I went with compile-time inheritance, and that means merging of
readtables.

  -T.


[*] For Lisp-down-to-the-metal implementations anyway. If pretty much
    anything is implemented in Lisp itself, you can often adapt an
    implementation in third-party code. And even for the case that your
    desired functionality will at some point be incoporated into the
    upstream version, that's still important for backwards
    compatibility.

    I didn't follow your clojure discussion that much, but that's among
    your gripes about it, isn't it?
From: D Herring
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <49d8ecd5$0$3338$6e1ede2f@read.cnntp.org>
budden wrote:
>   Rationale behind my design is that there
> is only a narrow namespace for readmacros.
> Moreover, CL suggests no way to resolve a
> clash. Consider library X which defines #?
> and your library which defines #? too. How
> do I use both libraries together? There are
> ugly workarounds to avoid the clash, but I
> know no really good solution.
>   Compare this to a way of resolving clashes
> between symbols:
> 
> package1:symbol and package2:symbol
> 
>   There is also import and use-package
> which allows to configure new package and choose
> which symbol(s) I prefer to enter w/o qualifier.

That's exactly what my read-macros package tried to solve.

Instead of doing dispatch on two characters (generally starting with 
#\#) my package claims a two-character metadispatch (by default #\# 
#\?) which then reads in the next symbol and dispatches on that.

So instead of having multiple libraries redefine #_, each should 
define a reader function (defun _ ...) but not register it with 
set-dispatch-macro-character.  The read-macros package will 
automatically start using it.

;; Example:
#?(_ a b c)     ; read using *package*:_
#?(foo:_ d e f) ; read using foo:_
#?(bar:_ g e h) ; read using bar:_

I need to write more documentation...


>   What I suggest is a way to alter reader's
> behavior for the scope of one form w/o occupying
> a single readmacro. Instead, I alter standard #.
> sequence by exposing a stream being read to a user.
> This seems to be a portable solution which allows to
> use "readsymbols" instead of readmacros thus
> allowing for really scalable syntax extensions.

I don't think its a good idea to modify "#.".  SBCL's looks clean, but 
other lisps may try hiding useful stuff in there.

That said, I'm interested in your use of *read-eval-stream*.  My 
approach was based on providing a simple layer over the built-in 
read-macro dispatch.  The goal was to provide a straightforward path 
for "upgrading" existing read macros.

Your approach, to define a new read-macro API, has some other perks. 
Particularly the ability to clearly identify arguments to the dispatch 
function in the source text.

What do you think of the following?  It builds on your system to 
expose all information available to a read macro.

;; alternate read-macro API
(defvar *read-macro-stream*)
(defvar *read-macro-subchar*)
(defvar *read-macro-infix-param*)
(defun dispatch (stream subchar infix-param)
   (let ((form (read stream t nil t))
         (*read-macro-stream* stream)
         (*read-macro-subchar* subchar)
         (*read-macro-infix-param* infix-param))
     (unless *read-suppress*
       (unless *read-eval*
         (error "bad dispatch on ~S while *read-eval* is nil" stream)))
     (eval form)))
(set-dispatch-macro-character #\# #\! #'dispatch)


;; Example 1
(defun with-package (designator)
   (let ((*package* (find-package designator)))
     (read *read-macro-stream* t nil t)))

(defparameter bar 1234)
(defpackage :foo (:use :cl) (:export :bar))
(defparameter foo:bar 42)
(+ bar bar) ; => 2468
#!(with-package :foo)(+ bar bar) ; => 84


;; Example 2
(defun with-magic (number)
   (+ (or *read-macro-infix-param* 0)
      number
      (eval (read *read-macro-stream* t nil t))))
#1!(with-magic 10)100 ; => 111


But some examples still look better in my :read-macros API.

#?(read-cond
     (= 1 2) :a
     (= 1 3) :b
     t :c) ; => :c

versus

#!(read-cond)
   ((= 1 2) :a
    (= 1 3) :b
    t :c) ; => :c

It may be best to provide both APIs and let the user choose whichever 
is most appropriate for the task at hand.

Later,
Daniel
From: D Herring
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <49d8f7a8$0$3338$6e1ede2f@read.cnntp.org>
budden wrote:
>   Rationale behind my design is that there
> is only a narrow namespace for readmacros.
> Moreover, CL suggests no way to resolve a
> clash. Consider library X which defines #?
> and your library which defines #? too. How
> do I use both libraries together? There are
> ugly workarounds to avoid the clash, but I
> know no really good solution.
>   Compare this to a way of resolving clashes
> between symbols:
> 
> package1:symbol and package2:symbol
> 
>   There is also import and use-package
> which allows to configure new package and choose
> which symbol(s) I prefer to enter w/o qualifier.

That's exactly what my read-macros package tried to solve.

Instead of doing dispatch on two characters (generally starting with 
#\#) my package claims a two-character metadispatch (by default #\# 
#\?) which then reads in the next symbol and dispatches on that.

So instead of having multiple libraries redefine #_, each should 
define a reader function (defun _ ...) but not register it with 
set-dispatch-macro-character.  The read-macros package will 
automatically start using it.

;; Example:
#?(_ a b c)     ; read using *package*:_
#?(foo:_ d e f) ; read using foo:_
#?(bar:_ g e h) ; read using bar:_

I need to write more documentation...


>   What I suggest is a way to alter reader's
> behavior for the scope of one form w/o occupying
> a single readmacro. Instead, I alter standard #.
> sequence by exposing a stream being read to a user.
> This seems to be a portable solution which allows to
> use "readsymbols" instead of readmacros thus
> allowing for really scalable syntax extensions.

I don't think its a good idea to modify "#.".  SBCL's looks clean, but 
other lisps may try hiding useful stuff in there.

That said, I'm interested in your use of *read-eval-stream*.  My 
approach was based on providing a simple layer over the built-in 
read-macro dispatch.  The goal was to provide a straightforward path 
for "upgrading" existing read macros.

Your approach, to define a new read-macro API, has some other perks. 
Particularly the ability to clearly identify arguments to the dispatch 
function in the source text.

What do you think of the following?  It builds on your system to 
expose all information available to a read macro.

;; alternate read-macro API
(defvar *read-macro-stream*)
(defvar *read-macro-subchar*)
(defvar *read-macro-infix-param*)
(defun dispatch (stream subchar infix-param)
   (let ((form (read stream t nil t))
         (*read-macro-stream* stream)
         (*read-macro-subchar* subchar)
         (*read-macro-infix-param* infix-param))
     (unless *read-suppress*
       (unless *read-eval*
         (error "bad dispatch on ~S while *read-eval* is nil" stream)))
     (eval form)))
(set-dispatch-macro-character #\# #\! #'dispatch)


;; Example 1
(defun with-package (designator)
   (let ((*package* (find-package designator)))
     (read *read-macro-stream* t nil t)))

(defparameter bar 1234)
(defpackage :foo (:use :cl) (:export :bar))
(defparameter foo:bar 42)
(+ bar bar) ; => 2468
#!(with-package :foo)(+ bar bar) ; => 84


;; Example 2
(defun with-magic (number)
   (+ (or *read-macro-infix-param* 0)
      number
      (eval (read *read-macro-stream* t nil t))))
#1!(with-magic 10)100 ; => 111


But some examples still look better in my :read-macros API.

e.g.
#?(read-cond
     (= 1 2) :a
     (= 1 3) :b
     t :c) ; => :c
versus
#!(read-cond)
   ((= 1 2) :a
    (= 1 3) :b
    t :c) ; => :c

or

#?(_ a b c)
versus
#!(_)(a b c)


It may be best to provide both APIs and let the user choose whichever 
is most appropriate for the task at hand.

Later,
Daniel
From: gugamilare
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <fced5fee-5cc0-45cb-8f46-86be57a97f0a@f11g2000vbf.googlegroups.com>
On 5 abr, 15:25, D Herring <········@at.tentpost.dot.com> wrote:
> budden wrote:
> >   Rationale behind my design is that there
> > is only a narrow namespace for readmacros.
> > Moreover, CL suggests no way to resolve a
> > clash. Consider library X which defines #?
> > and your library which defines #? too. How
> > do I use both libraries together? There are
> > ugly workarounds to avoid the clash, but I
> > know no really good solution.
> >   Compare this to a way of resolving clashes
> > between symbols:
>
> > package1:symbol and package2:symbol
>
> >   There is also import and use-package
> > which allows to configure new package and choose
> > which symbol(s) I prefer to enter w/o qualifier.
>
> That's exactly what my read-macros package tried to solve.
>
> Instead of doing dispatch on two characters (generally starting with
> #\#) my package claims a two-character metadispatch (by default #\#
> #\?) which then reads in the next symbol and dispatches on that.
>
> So instead of having multiple libraries redefine #_, each should
> define a reader function (defun _ ...) but not register it with
> set-dispatch-macro-character.  The read-macros package will
> automatically start using it.
>
> ;; Example:
> #?(_ a b c)     ; read using *package*:_
> #?(foo:_ d e f) ; read using foo:_
> #?(bar:_ g e h) ; read using bar:_
>
> I need to write more documentation...
>
> >   What I suggest is a way to alter reader's
> > behavior for the scope of one form w/o occupying
> > a single readmacro. Instead, I alter standard #.
> > sequence by exposing a stream being read to a user.
> > This seems to be a portable solution which allows to
> > use "readsymbols" instead of readmacros thus
> > allowing for really scalable syntax extensions.
>
> I don't think its a good idea to modify "#.".  SBCL's looks clean, but
> other lisps may try hiding useful stuff in there.
>
> That said, I'm interested in your use of *read-eval-stream*.  My
> approach was based on providing a simple layer over the built-in
> read-macro dispatch.  The goal was to provide a straightforward path
> for "upgrading" existing read macros.
>
> Your approach, to define a new read-macro API, has some other perks.
> Particularly the ability to clearly identify arguments to the dispatch
> function in the source text.
>
> What do you think of the following?  It builds on your system to
> expose all information available to a read macro.
>
> ;; alternate read-macro API
> (defvar *read-macro-stream*)
> (defvar *read-macro-subchar*)
> (defvar *read-macro-infix-param*)
> (defun dispatch (stream subchar infix-param)
>    (let ((form (read stream t nil t))
>          (*read-macro-stream* stream)
>          (*read-macro-subchar* subchar)
>          (*read-macro-infix-param* infix-param))
>      (unless *read-suppress*
>        (unless *read-eval*
>          (error "bad dispatch on ~S while *read-eval* is nil" stream)))
>      (eval form)))
> (set-dispatch-macro-character #\# #\! #'dispatch)
>
> ;; Example 1
> (defun with-package (designator)
>    (let ((*package* (find-package designator)))
>      (read *read-macro-stream* t nil t)))
>
> (defparameter bar 1234)
> (defpackage :foo (:use :cl) (:export :bar))
> (defparameter foo:bar 42)
> (+ bar bar) ; => 2468
> #!(with-package :foo)(+ bar bar) ; => 84
>
> ;; Example 2
> (defun with-magic (number)
>    (+ (or *read-macro-infix-param* 0)
>       number
>       (eval (read *read-macro-stream* t nil t))))
> #1!(with-magic 10)100 ; => 111
>
> But some examples still look better in my :read-macros API.
>
> e.g.
> #?(read-cond
>      (= 1 2) :a
>      (= 1 3) :b
>      t :c) ; => :c
> versus
> #!(read-cond)
>    ((= 1 2) :a
>     (= 1 3) :b
>     t :c) ; => :c
>
> or
>
> #?(_ a b c)
> versus
> #!(_)(a b c)
>
> It may be best to provide both APIs and let the user choose whichever
> is most appropriate for the task at hand.
>
> Later,
> Daniel

Your solution seems to be very good indeed.
From: budden
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <388c5008-b0a2-4ce1-a68b-fcae9967524f@s20g2000yqh.googlegroups.com>
Hi Daniel, list!
> That's exactly what my read-macros package tried to solve.
>
> Instead of doing dispatch on two characters (generally starting with
> #\#) my package claims a two-character metadispatch (by default #\#
> #\?) which then reads in the next symbol and dispatches on that.

> So instead of having multiple libraries redefine #_, each should
> define a reader function (defun _ ...) but not register it with
> set-dispatch-macro-character.  
First of all, if we are talking about the
way to interface existing libraries
in order to provide scalable readmacros,
it would be better to name that symbol
like hairy-readmacro-for-_ or so to
minimize a possibility of a conflict
with older symbols. It is easy to arrange
things so that it would read as a symbol
with the help of the following idea:

(defun unread-char* (char stream)
  "You can call unread-char* any number of times.
It returns a new stream to use instead of original stream"
  (make-concatenated-stream
    (make-string-input-stream
      (concatenate 'string (list char)))
       stream))
We "unread" a string "hairy-readmacro-for-"
and start reading again. Reader would see
hairy-readmacro-for-_

BTW, I'm designing more general solution:
a hack of a reader which would allow some
useful things like portable hierarchical
packages, portable package locks and custom
token parsers, see
http://groups.google.com/group/comp.lang.lisp/msg/c8db05c47b356562
and follow-ups.
One idea to put there is to
alter interpreation of package
qualifier. CL reads package
qualifier, then colons, then
symbol name. I suggest to read
package qualifier, then colons,
then bind *package* to
the package designated by a
qualifier and readtable
to the readtable associated with
the package, then call read
recursively.

This way,
foo::'(bar baz)
would return
'(foo::bar foo::baz)
and
foo::[some alien syntax]
would use #\[ reader from
a readtable associated
with the foo package.
This looks even more elegant than
#?foo::[some alien syntax]
but this design is not ideal still
as it does not allow for inheritance
of readmacros. Maybe symbol approach
is better here as we can import
"hairy-readmacro-" symbols as any
other ordinary symbols and so we
don't need a special infrastructure
for readtables.

> I don't think its a good idea to modify "#.".  
> SBCL's looks clean, but other lisps may try
> hiding useful stuff in there.

I think it is ok until someone reset a readtable
by using (copy-readtable nil). If it is not ok,
we can remember old #. reader and call it
from our new reader. Something like

(defvar |old-#.-reader|
  (get-dispatch-macro-character
   #\# #\.))

(defun |#.-reader| (s c n)
  (let1 *read-eval-stream* s
     (funcall |old-#.-reader| s c n)))

> What do you think of the following?  
*read-macro-infix-param* is useful. I'm not sure
*read-macro-subchar* adds some essential
information here. Again, I think that
altering #. is rather safe, but more real-life
testing is needed to be sure.

> #?(_ a b c)
> versus
> #!(_)(a b c)
It looks like your syntax is better when
surrounding parens are appropriate and
no additional arguments are passed. This
is sometimes true, but not always.

I don't know how to generalize it further,
really... Maybe we could use symbol
properties for storing our choice of the
behaviour. E.g. if
(get 'hairy-readmacro-for-_ :parens&no-args)
is true, then
#!(_ a b c) acts as yours #!, if nil, it
acts as mine #.(_)(a b c).
Also we could store kind of surrounding
delimiters in a property list, e.g., in
a property named :surrounding-delimiters. If
it is '(#\[ #\]), then we expect user to
type in something like
#![_ a b c]
I'm not sure which design is optimal here.
If we are going to get
somelib::\[-reader from some lib and make
somelib::hairy-readmacro-for-[ to call it,
we need not closing delimiter, but need only
an opening one as \[-reader would find
closing #\] itself. So there is still some
work to be done on design.
From: Kaz Kylheku
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <20090507062934.619@gmail.com>
On 2009-04-04, budden <···········@mail.ru> wrote:
> Also we can write
>> '(#.(in-package-1 :my-package) foo foo)
> and get
> '(my-package:foo foo)
>
> http://paste.lisp.org/display/78029

Uh, for fine-grained package control at read time, I developed
this:  http://paste.lisp.org/display/72068
From: budden
Subject: Re: A way to get rid of readmacros
Date: 
Message-ID: <327c04c4-9c13-46c7-96f2-574610cf519d@f1g2000prb.googlegroups.com>
> Uh, for fine-grained package control at read time, I developed
> this:  http://paste.lisp.org/display/72068
Nice! I see you have included another implementation of
my idea of see-packages that you seem have criticised
before. Did you finally came to conclusion that it
is useful?

Contrary to that, I'm disappointed in it. This
idea itself is fine, but not in a context of
existing CL IDEs. Read-time package juggling would
break definition search facility and migh occasionnaly
create trash symbols. So, any tool of this kind
should at least contain a patch to EMACS/SLIME.
And even this is not a full solution as users of
commercial IDEs still would suffer.

I think merge-packages-and-reexport works better
as it creates a new persistent package and it can
manage clashes automatically in a different ways.
So it won't break IDEs. The only problem is that
you have sometimes to re-run merged package
definition when you change base packages.

"Local package nicnames" seem to work even better
but I didn't try them yet. They do not create
new entities, but provide a tool to work with
existing packages in a more convinient manner.