[plt-scheme] read-delimited-list
Hi Matthias and Eli,
My earlier attempts to adapt readtables failed because I failed to
understand the docs. Your examples in this thread are very clear. May be
they deserve to be included in the help desk. I am facinated by the new
world of tools for the definition of customized languages with just a tiny
bit of programming. Yet I have two questions as displayed in the example
below. Be assured that they are not ment to be interpreted as a critic. I
merely wonder whether ot not it would be possible to tune MzScheme's
read-tables such as to avoid the pittfalls I fell into.
;;; module my-reader
;;; {var ... expr} ==> (lambda (var ...) expr) ; mark the braces
;;; ~ expr ==> (some-syntax expr)
(module my-reader mzscheme
(provide special-lambda)
; it would be nice not to be obliged to export this syntax (question 1: is
there a way???)
(define-syntax special-lambda
(syntax-rules ()
((special-lambda (var ... expr)) (lambda (var ...) expr))))
(define read-braces
(case-lambda
((ch port src line col pos)
#`(special-lambda #,(read/recursive port #\{ #f)))
; very nice: unquote-splicing-syntax accepted
((ch port) `(special-lambda ,(read/recursive port #\{ #f)))))
; unquote-splicing not accepted (understandible, but not consistent,
this is question 2)
(define read-tilde
(case-lambda
((ch port src line col pos) #`(some-syntax #,(read/recursive port #f
(current-readtable))))
((ch port) `(some-syntax ,(read/recursive port #f
(current-readtable))))))
(current-readtable
(make-readtable #f
#\{ 'terminating-macro read-braces
#\~ 'terminating-macro read-tilde)))
(require my-reader)
(define-syntax some-syntax
; This syntax could be defined in the module, but would have to be exported
anyway, I think.
(syntax-rules ()
((some-syntax x) (printf "from some-syntax ~s~n" 'x))))
~ 1 ; displays: from some-syntax 1
({a b c a} "a" "b" "c") ; --> "a"
(read (open-input-string "~ 2")) ; --> (some-syntax 2)
(read (open-input-string "({x y z x} 'x 'y 'x)")) ; --> error:
unquote-splicing: expected argument of type <proper list>; given
#<placeholder>
Be assured I am a fan of PLT, Jos Koot.
((((lambda(x)((((((x x)x)x)x)x)x))
(lambda(x)(lambda(y)(x(x y)))))
(lambda(x)(write x)x))
"greetings, Jos")
----- Original Message -----
From: "Eli Barzilay" <eli at barzilay.org>
To: "Matthew Flatt" <mflatt at cs.utah.edu>
Cc: <plt-scheme at list.cs.brown.edu>
Sent: Sunday, August 20, 2006 1:24 AM
Subject: Re: [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!
> _________________________________________________
> For list-related administrative tasks:
> http://list.cs.brown.edu/mailman/listinfo/plt-scheme