[plt-scheme] read-delimited-list

From: Jos Koot (jos.koot at telefonica.net)
Date: Sun Aug 20 17:47:22 EDT 2006

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 



Posted on the users mailing list.