guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

doc srfi-10 #,()


From: Kevin Ryde
Subject: doc srfi-10 #,()
Date: Thu, 02 Sep 2004 09:24:01 +1000
User-agent: Gnus/5.110003 (No Gnus v0.3) Emacs/21.3 (gnu/linux)

A bit of an expansion of the srfi-10 docs, trying to make the quoting
business clearer, and give more examples.


3.1.1 SRFI-10 - Hash-Comma Reader Extension
-------------------------------------------

This SRFI implements a reader extension `#,()' called hash-comma.  It
allows the reader to return new kinds of objects, for use both in data
and as constants or literals in source code.  This feature is available
with

     (use-modules (srfi srfi-10))

The new read syntax is of the form

     #,(TAG ARG...)

where TAG is a symbol and the ARGs are objects taken as parameters.
TAGs are registered with the following procedure.

 -- Scheme Procedure: define-reader-ctor tag proc
     Register PROC as the constructor for a hash-comma read syntax
     starting with symbol TAG, ie. #,(TAG arg...).  PROC is called with
     the given arguments `(PROC arg...)' and the object it returns is
     the result of the read.

For example, a syntax giving a list of N copies of an object.

     (define-reader-ctor 'repeat
       (lambda (obj reps)
         (make-list reps obj)))

     (display '#,(repeat 99 3))
     -| (99 99 99)

   Notice the quote ' when the #,( ) is used.  The `repeat' handler
returns a list and for the program to use that literally it must be
quoted the same as any other list.  Ie.

     (display '#,(repeat 99 3))
     =>
     (display '(99 99 99))

   When a handler returns an object which is self-evaluating, like a
number or a string, then there's no need for quoting, just as there's
no need when giving those directly as literals.  For example a simple
addition,

     (define-reader-ctor 'sum
       (lambda (x y)
         (+ x y)))
     (display #,(sum 123 456)) -| 579

   A typical use for #,() is to get a read syntax for objects which
don't otherwise have one.  For example, the following allows a hash
table to be given literally, with tags and values, ready for fast
lookup.

     (define-reader-ctor 'hash
       (lambda elems
         (let ((table (make-hash-table)))
           (for-each (lambda (elem)
                  (apply hash-set! table elem))
                elems)
           table)))

     (define (animal->family animal)
       (hash-ref '#,(hash ("tiger" "cat")
                          ("lion"  "cat")
                          ("wolf"  "dog"))
                 animal))

     (animal->family "lion") => "cat"

   Or for example the following is a syntax for a compiled regular
expression (*note Regular Expressions::).

     (use-modules (ice-9 regex))

     (define-reader-ctor 'regexp make-regexp)

     (define (extract-angs str)
       (let ((match (regexp-exec '#,(regexp "<([A-Z0-9]+)>") str)))
         (and match
              (match:substring match 1))))

     (extract-angs "foo <BAR> quux") => "BAR"


   #,() is somewhat similar to `defmacro' (*note Macros::) in that
handler code is run to produce a result, but #,() operates at the read
stage, so it can appear in data for `read' (*note Scheme Read::), not
just in code to be executed.

   Because #,() is handled at read-time it has no direct access to
variables etc.  A symbol in the arguments is just a symbol, not a
variable reference.  The arguments are essentially constants, though
the handler procedure can use them in any complicated way it might want.

   Once `(srfi srfi-10)' has loaded, #,() is available globally,
there's no need to use `(srfi srfi-10)' in later modules.  Similarly
the tags registered are global and can be used anywhere once registered.

   There's no attempt to record what previous #,() forms have been
seen, if two identical forms occur then two calls are made to the
handler procedure.  The handler might like to maintain a cache or
similar to avoid making copies of large objects, depending on expected
usage.

   In code the best uses of #,() are generally when there's a lot of
objects of a particular kind being used as literals or constants.  If
there's just a few then some local variables and initializers are fine,
but that becomes tedious and error prone when there's a lot and the
anonymous and compact syntax of #,() is much better.




reply via email to

[Prev in Thread] Current Thread [Next in Thread]