define-reader-ctor is merely an implementation hint oleg@xxxxxx (05 Oct 1999 18:44 UTC)
|
Re: define-reader-ctor is merely an implementation hint
Richard Kelsey
(05 Oct 1999 19:25 UTC)
|
Re: define-reader-ctor is merely an implementation hint
Marc Feeley
(05 Oct 1999 20:01 UTC)
|
> The only way to supply contructor functions in SRFI-10 is by doing > (define-reader-ctor <symbol> <proc>). No. The only requirement SRFI-10 mandates is that "There must be a way to declare an association between a symbolic tag and the corresponding constructor-procedure." SRFI-10 goes on to _suggest_ that an implementation may want to implement a define-reader-ctor function for that purpose. SRFI-10 does not say that define-reader-ctor is the required method to build tag-constructor associations, let alone that it is the only method (see also below). > The reader is used in two different ways: it is used to read > the original program and it is used when that program calls > `read'. But how can a program modify the reader that was used > to read it? <blockquote cite="SRFI-10#last-but-two-paragraph"> The remaining question is how and when to define reader-constructors. If define-reader-ctor is a regular function, declaration of a new reader-constructor will affect the Scheme reader only when the code has been completely read, (byte)compiled and is being executed. We would like to be able to extend the Scheme reader while it still reads the code. Fortunately, there are several ways to affect a compiler/interpreter while it scans the code. For example, define-macro or define-syntax "extend" a Scheme compiler at compile time. So do command-line switches and pragmas, which are present in many systems. In addition, Scheme implementations often permit customization via profile forms, which may also be specified on command line. </blockquote> Here is one example how this can be accomplished. Let's assume we have a Scheme-to-C compiler scc, which supports R5RS and SRFI-10. Let's assume that this compiler is extensible: it is capable of loading "shared objects". Let us assume that srfi-4.so is a shared object that implements uniform vectors; among other procedures, it defines f32vector constructor, and adds association between 'f32 and this constructor. This shared object also defines a "feature" srfi-4 (per SRFI-0). If I have a Scheme source code file containing (define (temp-proc) (let ((v '#,(f32 1.0 2.0 3.0))) (f32vector-ref v 1))) I can compile it as scc -e srfi-4.so filename.scm srfi-4.so may originally be written in Scheme, C, assembly etc. The source language for f32vector constructor is irrelevant, as long as it can take Scheme values and return a Scheme value, in a manner consistent with the rest of the compiler. This scenario isn't that hypothetical as it sounds. Gambit Scheme Compiler and interpreter permit a user specify pieces of code to be executed at compiler's start-up time. These pieces can be given in various profile files, or on the command line. The following excerpt from http://pobox.com/~oleg/ftp/Scheme/vcond-expand.scm shows how to modify a Gambit Scheme interpreter before it started evaluating user's code. The modification includes enabling SRFI-10, SRFI-0, and building a list of features. ; Interpret file file-name given feature-list (define (with-features feature-list file-name) (cerr "\n\twhen features " feature-list " are defined: ") (OS:system "gsi -e '(##include \"cond-expand.scm\")' " "-e \"(define ALL-FEATURES '" (with-output-to-string (lambda () (write feature-list))) ")\" " file-name)) BTW, the Gambit Scheme system also permits loading of shared objects, for example, at start-up time. Making a shared object is such a hassle however. I admit SRFI-10's normative silence about precise ways to define reader-constructor associations may sound like a cop-out. Yet is is intentional: the purpose of SRFI-10 is to extend the _protocol_ by which a Scheme system communicates with an external world. If my and your applications run by a SRFI-10-compliant system, and I send you a string "#,(f32 1.0 2.0 3.0)" then you know what I am trying to say. What you're going to do about this -- reject or accept my request for constructing a value -- is another matter entirely. I don't think SRFI-10 is way out of the line in this respect. For example, SRFI-0 talks about feature identifiers -- yet it gives no details how an implementation happens to have these identifiers defined, and how a user may extend the system with more identifiers (if he can at all). > (make-reader) -> <reader> > (extend-reader <reader> <symbol> <proc>) -> <reader> > A <reader> is function of one argument, an input port, that > reads and returns the next s-expression from the port. > (<reader> <input-port>) -> <s-expression> > `Make-reader' returns a reader that parses the R5RS external > syntax. `Extend-reader' returns a new reader that is the same > as its first argument except that it uses <proc> as a constructor > when it finds #,(<symbol> . <args>) in the input, as is done > in SRFI-10. And thus you have outlined another implementation of SRFI-10. BTW, the reference implementation is not that different. Gambit's reader is written in R4RS Scheme. I extend it _slightly_ to handle a #,() form. Instead of (make-reader) procedure I rely on a _readtable_ (which Gambit supports). Readtables also offer modularity, and a possibility to have multiple different readers in a program. Again, the reader and my extension are written entirely in R4RS, and support a superset of R4RS (including SRFI-10). > It has the added advantages of being modular ... and being easy to > implement in R5RS. I'm afraid I'm a bit confused by mentioning of ease of implementation in R5RS. A R5RS-compliant system can certainly be implemented in R4RS Scheme. That does not mean that R5RS is somehow redundant.