[plt-scheme] read-delimited-list
On Aug 19, Matthew Flatt wrote:
> At 18 Aug 2006 23:09:54 -0000, Paul Graham wrote:
> > Is there some equivalent of cl read-delimited-list in mzscheme?
> >
> > I'm trying to make [foo _ bar] read as (lambda (_) (foo _ bar)).
>
> You can get something like `read-delimited-list' by using
> `read/recursive' using #f to indicate the default readtable:
>
> (define (read-square-brackets ch port src line col pos)
> `(lambda ()
> ;; Recursive read starts with default readtable's [ parser,
> ;; but nested reads still use the curent readtable:
> ,(read/recursive port #\[ #f)))
>
> (parameterize ([current-readtable
> (make-readtable #f
> #\[ 'terminating-macro read-square-brackets)])
> (read (open-input-string "[foo _ bar]")))
There is a missing part there -- the injected `lambda' doesn't have
the `_' binding... This should work as expected:
(define (read-square-brackets ch port src line col pos)
`(lambda (_)
;; Recursive read starts with default readtable's [ parser,
;; but nested reads still use the curent readtable:
,(read/recursive port #\[ #f)))
but I think that there is not enough examples around for playing with
readtables, so I'll give some more details. (So this is going to be a
little verbose.)
There are two ways to play with readtables in mzscheme -- changing the
`current-readtable' parameter or using the #reader syntax. The first
is a little easier to play with when you're trying to play with the
new reader but the global change is not something you want (in this
case, there is a lot of PLT code that uses brackets for a completely
different purpose, so if you happen to load some library through
source code, you're likely to get some weird errors); so this method
is better for reader extensions that do not affect a lot of existing
code (like adding some new `#' reader). The second approach avoids
the global change, so it is better for actually using it, for test
cases and for `real' code that uses the new table. To implement the
first, all you need is some code that changes the global readtable,
and to implement the second, you need a module that provides custom
`read' and `read-syntax' functionality.
I usually like to make both ways available, by putting the code in a
module that provides `read', `read-syntax', and a `use-xxx-readtable'
for the global change. In this case, I put this in a "r.scm" file:
(module r mzscheme
;; The main reader function for []s
(define (read-square-brackets ch port src line col pos)
`(lambda (_)
;; Recursive read starts with default readtable's [ parser,
;; but nested reads still use the curent readtable:
,(read/recursive port #\[ #f)))
;; A readtable that is just like the builtin except for []s
(define bracket-readtable
(make-readtable #f #\[ 'terminating-macro read-square-brackets))
;; Call this to set the global readtable
(provide use-bracket-readtable)
(define (use-bracket-readtable)
(current-readtable bracket-readtable))
;; These two implement the required functionality for #reader
(define (*read inp)
(parameterize ([current-readtable bracket-readtable])
(read inp)))
(define (*read-syntax src port)
(parameterize ([current-readtable bracket-readtable])
(read-syntax src port)))
;; ... and the need to be provided as `read' and `read-syntax'
(provide (rename *read read) (rename *read-syntax read-syntax)))
Once that's in a file, I risk trying it using a global change:
Welcome to MzScheme version 352, Copyright (c) 2004-2006 PLT Scheme Inc.
> (require "r.scm")
> (use-bracket-readtable)
> ([+ _ 1] 10)
11
or I can use the safer #reader to change the meaning of a single
expression:
Welcome to MzScheme version 352, Copyright (c) 2004-2006 PLT Scheme Inc.
> #reader"r.scm" (define (foo l) (map [* _ 2] l))
> (foo '(1 2 3))
(2 4 6)
> #reader"r.scm" (define (foo l) (map [map [* _ 2] _] l))
> (foo '((1 2 3) (4 5 6 7)))
((2 4 6) (8 10 12 14))
Since #reader changes the table for the following item, it can be used
for whole modules in a convenient way:
#reader"r.scm"
(module xx mzscheme
(provide foo)
(define (foo l) (map [map [* _ 2] _] l)))
There's a bunch of stuff that is useful to know about custom
readtables that I didn't mention, like how to create the syntax
objects explicitly, etc -- but in this case the default behavior is
working fine.
Also, the interface for using readtables might be extended -- it seems
that some command-line flags could be useful, but no conclusion
reached (yet). (See PR7374)
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://www.barzilay.org/ Maze is Life!