by Wolfgang Corcoran-Mathe
For editor's use only. Please do not edit this section.
??? the draft/final/withdrawn status of the SRFI, information on how to subscribe to its mailing list, and important dates in its history. The editor will add this section.
An uninterned symbol is not the same as any other symbol, even one with the same name. These symbols are useful in macro programming and in other situations where guaranteed-unique names are needed. A lexical syntax for uninterned symbols is described, allowing uninterned literal symbols to appear in program source and macro templates. A survey of uninterned and uniquely-named symbols in Scheme is also provided.
None at present.
A characteristic property of symbols in Scheme is that “two symbols
are identical (in the sense of eqv?
) if and only if their
names are spelled the same way” (R7RS section 6.5). Such
symbols are traditionally known as interned symbols. It is
sometimes useful, however, to create uninterned symbols
that are different from all other symbols, even those with the same
textual name.
Many Scheme implementations provide uninterned symbols, and they are also part of the ANSI Common Lisp standard. Their use is almost mandatory with unhygienic macro systems (like that of Common Lisp), where they are used as hidden names that cannot be accidentally captured. This issue is largely solved by Scheme’s hygienic macro systems, but uninterned symbols still have their uses in Scheme macro programming. They can be used as unique keys shared between communicating macros or procedures, for example, since there is no possibility of collision between uninterned and user-created symbols.
The traditional way to create a unique symbol is through a
gensym
procedure. The name of this procedure is
ubiquitous: it dates back at least as far as LISP 1.5, and a variant of
gensym
is provided by almost every Scheme implementation.
It should come as no surprise that the behavior of these
gensym
procedures varies
widely; in particular, many gensym
s return interned
symbols (see the survey
below for details). To increase
compatibility with existing implementations, this document specifies
generate-uninterned-symbol
, a gensym
-like
procedure, and
another constructor, string->uninterned-symbol
, which
is consistent across the Scheme implementations that provide it.
In this document, a symbol’s textual name refers to
the string returned when symbol->string
is invoked
on the symbol.
An uninterned symbol is a symbol (in the sense of
symbol?
) which is not identical (in the sense of
symbol=?
) with any other symbol, even a symbol with the
same textual name.
Uninterned symbols do not support the write/read invariance
described in R7RS section 6.5: if an uninterned symbol is
written out with write
and then read back in, the
resulting symbol is not identical (in the sense of
symbol=?
) to the original symbol.
(string->uninterned-symbol
string)
→
Returns an uninterned symbol with a textual name given by string.
(symbol-interned?
symbol
)
→
Returns #t
if symbol is an interned (ordinary)
symbol, and #f
if it is uninterned.
(generate-uninterned-symbol
[prefix])
→
Returns an uninterned symbol with a textual name that is likely to be unique. If the optional prefix argument is provided and is a string / symbol, then prefix / the name of prefix is prepended to the resulting symbol’s name.
generate-uninterned-symbol
duplicates the behavior of
gensym
in Scheme implementations that provide uninterned
symbols (and in which gensym
returns an uninterned
symbol).
Following Common Lisp, many
gensym
implementations use a non-negative integer
counter, a representation of the value of which is appended to
the name of the returned symbol. Each call to gensym
increments this counter. Other implementations use Universally
Unique Identifiers (UUIDs) (ITU-T Rec. X.667, ISO/IEC
9834-8:2014) as names.
Uninterned symbols are written using the notation
:|
identifier|
, where
identifier belongs to the class of valid Scheme
identifiers defined in R7RS § 7.1.1. Example:
(symbol->string :|srfi|)
⇒"srfi" (symbol-interned? :|srfi|)
⇒#f
More formally, this SRFI extends the syntax of Scheme as described in § 7.1 of the R7RS as follows. The following production is added to § 7.1.1:
uninterned symbol ⟶:|
identifier|
The following production of § 7.1.2 is extended:
simple datum ⟶ boolean | … | uninterned symbol
Similarly, in § 7.1.3:
self-evaluating ⟶ boolean | … | uninterned symbol
And in § 7.1.5:
pattern datum ⟶ boolean | … | uninterned symbol
Implementation | Uninterned symbols | gensym |
gensym prefix argument |
gensym interned |
string->uninterned-symbol |
---|---|---|---|---|---|
Bigloo | No | Yes | String or symbol | Yes | No |
ChezScheme | Yes | Yes | String | Yes | Yes |
CHICKEN | Yes | Yes | String or symbol | No | Yes |
Cyclone | No | Yes | String or symbol | Yes | No |
Gambit | Yes | Yes | Symbol | No | Yes |
Guile | Yes | Yes | String | Yes | No |
Ikarus | No | Yes | String | Yes | No |
Kawa | No | No* | n/a | n/a | No |
Larceny | Yes | Yes | String | No | No |
Loko | Yes | Yes | None | No | No |
MIT/GNU Scheme | Yes | No† | n/a | n/a | Yes |
Racket | Yes | Yes | String or symbol | No | Yes |
TinySCHEME | No | Yes | None | Yes | No |
*: Kawa includes a
zero-argument gentemp
procedure that returns an interned
symbol.
†: MIT/GNU Scheme provides generate-uninterned-symbol, an extended version of the procedure described above.
Chez provides interned “gensyms” which are distinguished by the
gensym?
predicate. Chez’s gensyms have “pretty” and
“unique” names. The former are created immediately and the latter are
generated lazily using an internal prefix and counter, which are
accessible through parameter objects.
gensym->unique-string
returns the unique name of a
gensym.
Chez’s gensym
procedure takes optional
pretty-name and unique-name string arguments.
The latter argument allows the unique name of one gensym to be given
to another; thus, distinct gensyms that are equal in the sense of
symbol=?
can be created in Chez.
See section 7.9 of the ChezScheme User’s Guide for further details.
Uninterned symbols are used extensively in Common Lisp macro
programming. The Common Lisp
HyperSpec specifies
MAKE-SYMBOL
(analogous to string->uninterned-symbol
) and
GENSYM
procedures that construct uninterned symbols. The names of the
symbols returned by GENSYM
usually include the value
of *GENSYM-COUNTER*
, a non-negative integer variable,
which is incremented by each call to GENSYM
. (This
behavior can be circumvented by providing an explicit suffix to
GENSYM
. See the CLHS for details.)
Since Common Lisp does not have Scheme’s distinction between symbols and identifiers, the implications of internedness are much broader in Common Lisp. For example, objects named by uninterned symbols are, in effect, private to the package in which they were defined. A full discussion of uninterned symbols in Common Lisp is beyond the scope of this SRFI.
A portable implementation of uninterned symbols is impossible. In
Scheme implementations that provide them (see the table above),
uninterned symbols and string->uninterned-symbol
are
generally compatible with this SRFI.
Many Scheme implementations maintain a table of symbols, indexed by name. When a symbol is created, its name is looked up in this table; if a symbol with that name exists, it is returned; otherwise, a fresh symbol is added to the table. In implementations that use this or a similar strategy, uninterned symbols may be provided by simply skipping the table-lookup and insertion steps.
Thanks to Daphne Preston-Kendal for pushing for this SRFI and to Marc Nieper-Wißkirchen for challenging almost everything in it.
Thanks to those who provided reviews and commentary via the SRFI mailing list or the #scheme IRC channel.
Alex Shinn, John Cowan, & Arthur A. Gleckler, eds., Revised7 Report on the Algorithmic Language Scheme (R7RS Small) (2013). Available on the Web.
Kent M. Pitman, et al, eds., Common Lisp HyperSpec™ (CLHS) (1994). Available on the Web.
Cisco Systems, Inc., Chez Scheme User’s Guide (2015). Available on the Web.
© 2025 Wolfgang Corcoran-Mathe
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next paragraph) shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Editor: Arthur A. Gleckler