[plt-scheme] Understanding readtables

From: Eli Barzilay (eli at barzilay.org)
Date: Fri Jul 4 17:03:30 EDT 2008

A few relevant notes:

On Jul  4, Mark Engelberg wrote:
> [...]
> Okay, now he's created a custom write function that displays a bundle
> as #*((+ 1 2) . 3)
> He wants to customize the reader so that he can read back in this
> printed version of the bundle, sort of like #(1 2 3) for making
> vectors, or #hash((1 . 2)) for making a hash table.  He ideally
> envisions that the reader would handle either #*((+ 1 2) . 3) or
> #*((+ 1 2)) and it will return #*((+ 1 2) . 3)

What about #*((+ 1 2) . 5) ?

Also, it's wrong to think of it as "returning" a value.  Better to
think of it as what it translates to as a new piece of syntax.  For
example, make #*(<X> . <Y>) translate to (bundle <X> <Y>), which has
an implication if you put it inside quote, for example.  (And in an
answer to the above, I imagine `bundle' with a second argument testing
that value and throwing an error if it's wrong.)

The reason for this is that otherwise you get into problems with
evaluating an expression at read-time, which is usually going to be a
bad idea.  For example, you probably want this to work:

  (let ([x 1])
    #*((+ x 2) . 3))

> So from the documentation, it sounds like he needs to extend the
> readtable with a dispatch-macro, that calls a special reading
> function that will be called when the reader is called for #*.
> Something like:
> (current-readtable (make-readtable (current-readtable) #\*
> 'dispatch-macro readerbundle))
> But this doesn't quite work, and it's not really clear what form
> this reader function needs to take.  Can someone set us on the right
> path here?

You can look in collects/scribble/reader.ss for an example.  You
generally want a function that gets

  char - the character that was used to call this function
  inp  - the input port
  source-name line-num col-num position - location information

and returns a piece of syntax.

Important things to remember:

* The syntax is best built with

    (datum->syntax #f <s-expression>
                   (vector ...location-info...)

  the first thing should be #f -- so you produce a syntax with no
  lexical information (that will be problematic since if you do that
  then it'll be the lexical context of the reader code that generated
  it or something similar).

* Changing the readtable with (current-readtable <foo>) is not a good
  idea since it's a side-effect, is use it only for testing.  Later
  on, it's best to write a module that provide `read' and
  `read-syntax' and use it with something like

    #reader "my-reader.ss"

  and these functions will use `parameterize' to have a local change
  of the syntax only.  scribble/reader.ss has an example of that also
  (at the bottom of the file).

          ((lambda (x) (x x)) (lambda (x) (x x)))          Eli Barzilay:
                  http://www.barzilay.org/                 Maze is Life!

Posted on the users mailing list.