mirror of
https://git.savannah.gnu.org/git/guile.git
synced 2025-06-30 23:10:21 +02:00
Manual recommends against SRFI-10
* doc/ref/srfi-modules.texi (SRFI-10): Deprecate, or at least recommend against.
This commit is contained in:
parent
1a1c3bbe59
commit
e68dd5c601
1 changed files with 37 additions and 64 deletions
|
@ -1834,9 +1834,9 @@ documented in the ``Compound Data Types'' section of the manual
|
||||||
@cindex hash-comma
|
@cindex hash-comma
|
||||||
@cindex #,()
|
@cindex #,()
|
||||||
This SRFI implements a reader extension @code{#,()} called hash-comma.
|
This SRFI implements a reader extension @code{#,()} called hash-comma.
|
||||||
It allows the reader to give new kinds of objects, for use both in
|
It allows the reader to give new kinds of objects, for use both in data
|
||||||
data and as constants or literals in source code. This feature is
|
and as constants or literals in source code. This feature is available
|
||||||
available with
|
with
|
||||||
|
|
||||||
@example
|
@example
|
||||||
(use-modules (srfi srfi-10))
|
(use-modules (srfi srfi-10))
|
||||||
|
@ -1894,73 +1894,46 @@ addition,
|
||||||
(display #,(sum 123 456)) @print{} 579
|
(display #,(sum 123 456)) @print{} 579
|
||||||
@end example
|
@end example
|
||||||
|
|
||||||
A typical use for @nicode{#,()} 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.
|
|
||||||
|
|
||||||
@example
|
|
||||||
(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") @result{} "cat"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
Or for example the following is a syntax for a compiled regular
|
|
||||||
expression (@pxref{Regular Expressions}).
|
|
||||||
|
|
||||||
@example
|
|
||||||
(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") @result{} "BAR"
|
|
||||||
@end example
|
|
||||||
|
|
||||||
@sp 1
|
|
||||||
@nicode{#,()} is somewhat similar to @code{define-macro}
|
|
||||||
(@pxref{Macros}) in that handler code is run to produce a result, but
|
|
||||||
@nicode{#,()} operates at the read stage, so it can appear in data for
|
|
||||||
@code{read} (@pxref{Scheme Read}), not just in code to be executed.
|
|
||||||
|
|
||||||
Because @nicode{#,()} 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 @code{(srfi srfi-10)} has loaded, @nicode{#,()} is available
|
Once @code{(srfi srfi-10)} has loaded, @nicode{#,()} is available
|
||||||
globally, there's no need to use @code{(srfi srfi-10)} in later
|
globally, there's no need to use @code{(srfi srfi-10)} in later
|
||||||
modules. Similarly the tags registered are global and can be used
|
modules. Similarly the tags registered are global and can be used
|
||||||
anywhere once registered.
|
anywhere once registered.
|
||||||
|
|
||||||
There's no attempt to record what previous @nicode{#,()} forms have
|
We do not recommend @nicode{#,()} reader extensions, however, and for
|
||||||
been seen, if two identical forms occur then two calls are made to the
|
three reasons.
|
||||||
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 @nicode{#,()} are generally when there's a
|
First of all, this SRFI is not modular: the tag is matched by name, not
|
||||||
lot of objects of a particular kind as literals or constants. If
|
as an identifier within a scope. Defining a reader extension in one
|
||||||
there's just a few then some local variables and initializers are
|
part of a program can thus affect unrelated parts of a program because
|
||||||
fine, but that becomes tedious and error prone when there's a lot, and
|
the tag is not scoped.
|
||||||
the anonymous and compact syntax of @nicode{#,()} is much better.
|
|
||||||
|
Secondly, reader extensions can be hard to manage from a time
|
||||||
|
perspective: when does the reader extension take effect? @xref{Eval
|
||||||
|
When}, for more discussion.
|
||||||
|
|
||||||
|
Finally, reader extensions can easily produce objects that can't be
|
||||||
|
reified to an object file by the compiler. For example if you define a
|
||||||
|
reader extension that makes a hash table (@pxref{Hash Tables}), then it
|
||||||
|
will work fine when run with the interpreter, and you think you have a
|
||||||
|
neat hack. But then if you try to compile your program, after wrangling
|
||||||
|
with the @code{eval-when} concerns mentioned above, the compiler will
|
||||||
|
carp that it doesn't know how to serialize a hash table to disk.
|
||||||
|
|
||||||
|
In the specific case of hash tables, it would be possible for Guile to
|
||||||
|
know how to pack hash tables into compiled files, but this doesn't work
|
||||||
|
in general. What if the object you produce is an instance of a record
|
||||||
|
type? Guile would then have to serialize the record type to disk too,
|
||||||
|
and then what happens if the program independently loads the code that
|
||||||
|
defines the record type? Does it define the same type or a different
|
||||||
|
type? Guile's record types are nominal, not structural, so the answer
|
||||||
|
is not clear at all.
|
||||||
|
|
||||||
|
For all of these reasons we recommend macros over reader extensions.
|
||||||
|
Macros fulfill many of the same needs while preserving modular
|
||||||
|
composition, and their interaction with @code{eval-when} is well-known.
|
||||||
|
If you need brevity, instead use @code{read-hash-extend} and make your
|
||||||
|
reader extension expand to a macro invocation. In that way we preserve
|
||||||
|
scoping as much as possible. @xref{Reader Extensions}.
|
||||||
|
|
||||||
|
|
||||||
@node SRFI-11
|
@node SRFI-11
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue