summaryrefslogtreecommitdiff
path: root/artima
diff options
context:
space:
mode:
authormichele.simionato <devnull@localhost>2009-08-06 05:13:04 +0000
committermichele.simionato <devnull@localhost>2009-08-06 05:13:04 +0000
commit7765209e4ac6b0fbd8562160ceae73a22ca215e8 (patch)
treec097eab2c88aa81729754e621ab7b035a87ba0c6 /artima
parent26ba29e87b77aedbf0eb5e0e521725384a5c546b (diff)
downloadmicheles-7765209e4ac6b0fbd8562160ceae73a22ca215e8.tar.gz
Published scheme30
Diffstat (limited to 'artima')
-rw-r--r--artima/scheme/identity.pngbin0 -> 1005 bytes
-rw-r--r--artima/scheme/index.rst6
-rw-r--r--artima/scheme/scheme30.ss179
-rw-r--r--artima/scheme/table-of-contents.txt6
4 files changed, 107 insertions, 84 deletions
diff --git a/artima/scheme/identity.png b/artima/scheme/identity.png
new file mode 100644
index 0000000..673af87
--- /dev/null
+++ b/artima/scheme/identity.png
Binary files differ
diff --git a/artima/scheme/index.rst b/artima/scheme/index.rst
index 5719acf..807c83b 100644
--- a/artima/scheme/index.rst
+++ b/artima/scheme/index.rst
@@ -34,6 +34,12 @@ Contents:
scheme22
scheme23
scheme24
+ scheme25
+ scheme26
+ scheme27
+ scheme28
+ scheme29
+ scheme30
Indices and tables
==================
diff --git a/artima/scheme/scheme30.ss b/artima/scheme/scheme30.ss
index 231c8d9..6d5a4cb 100644
--- a/artima/scheme/scheme30.ss
+++ b/artima/scheme/scheme30.ss
@@ -1,31 +1,32 @@
#|Comparing identifiers
=================================================
-Equality of identifiers is one of the trickiest things in R6RS
-Scheme, since the meaning of identifier equality in a lexically
-scoped language with hygienic macros is non-obvious.
-
-Identifier equality is a compile-time
+This is the last episode of part V of my Adventures. In the latest
+episodes I have discussed various technicalities of Scheme macros,
+such as the concepts of syntax object, hygiene and lexical context.
+There is still an important subject to be discuss in order to
+become really proficient with Scheme macros: *identifier equality*.
+Equality of identifiers is one of the trickiest things in
+Scheme.
+
+First of all, identifier equality is a compile-time
concept which has nothing to do with the run-time concept of equality
-between variables: two variables are equal if their underlying values
-are equal, but the value to which a variable is bound is only known
-at run-time, therefore identifier equality cannot rely on it.
-
+between variables.
Identifiers are not variables: they are syntax objects with an
underlying symbol and an underlying lexical context, which are known
statically at compile time. It is possible to know if an
identifier is bound or not at compile-time, but the value the
-identifier will be bound to at run-time is unknown.
+identifier will be bound to at run-time is (in general) unknown.
-The Scheme standard define two different equality procedures
-for identifiers (``bound-identifier=?`` and ``free-identifier=?``,
-with absolutely misleading names); to those, I will add a third one,
-``symbol-identifier=?``.
+Secondly, there is not a single concept of identifier equality,
+but different definitions are possible. In this episode I will
+discuss three different predicates to compare identifiers:
+``symbol-identifier=?``, ``bound-identifier=?`` and ``free-identifier=?``
+(the latter two are part of the R6RS standard).
-This episode will be spent discussing the subtilities of identifier
-equality.
+.. image:: identity.png
-.. image:: Love_equality.png
+.. _22: http://www.artima.com/weblogs/viewpost.jsp?thread=256848
``symbol-identifier=?``
-----------------------------------------------
@@ -33,22 +34,21 @@ equality.
The simplest concept of identifier equality is expressed by
the following ``symbol-identifier=?`` comparison function
(for convenience, I have added the ``symbol-identifier=?``
-precedure in the ``(aps lang)`` library):
+precedure to the ``(aps lang)`` library):
$$lang:SYMBOL-IDENTIFIER=?
Two identifiers are ``symbol-identifier=?`` if they are equal as
-symbols.
+symbols, once their lexical information has been stripped out.
-``symbol-identifier=?`` can
-be used to manage duplicate names in macros defining multiple
-identifiers at once, or in macros defining name->value tables, such as
-the ``static-map`` I discussed in episode 22. Moreover,
+For instance, ``symbol-identifier=?`` can
+be used to find duplicated names in macros defining ``name->value``
+tables, such as the ``static-map`` macro I discussed in episode 22_. Moreover,
``symbol-identifier=?`` can be used to reject reserved
identifiers (you may need such
-functionality if are buildin a mini-language on top of Scheme
+functionality if are building a mini-language on top of Scheme
and you want to reject a few identifiers as language keywords), as
-in the following macro:
+in the following example:
$$CHECK-RESERVED
@@ -68,24 +68,22 @@ I wrote, in episode 9_:
#'(begin (define name1 value1) (define name2 value2) ...))
It is quite common to write macros defining multiple bindings, such
-as ``multi-define``. There is also the common situation of
-macros which expand themselves to macros defining
-multiple bindings. When code is generated automatically, errors are
-more than likely and it makes sense to manage explicitly
-the situation when the list of names to be defined contains some
-duplicate. ``multi-define`` as written does not perform any check, so that it
+as ``multi-define``.
+``multi-define`` as written does not perform any check for duplicated
+identifiers, so that it
relies on the standard behavior of R6RS scheme, raising an error.
-Unfortunately, the standard behavior only applies to programs and scripts,
-whereas the REPL is quite free to behaves differently and indeed it does:
+However, the standard behavior only applies to programs and scripts,
+whereas the REPL is quite free to behaves differently and indeed it does
+in most implementations:
.. code-block:: scheme
- > (multi-define (a a) (1 2))
+ > (multi-define (a a) (1 2)); in Ikarus, Ypsilon, ...
a
2
-(in the REPL latter definitions override previous definitions). Being
-unhappy with that, we can introduce a ``bound-identifier=?`` check
+(in the REPL latter definitions override previous definitions).
+If you are unhappy with that, you can introduce a ``bound-identifier=?`` check
and raise a custom exception:
$$MULTI-DEFINE
@@ -110,13 +108,13 @@ identifiers:
form: (a a)
subform: #f
-You may also believe that using ``symbol-identifier=?`` would work too.
-However this is not the case, in general. Consider
+In this simple example using ``symbol-identifier=?`` would work too.
+However this is not the geneal case. Consider
for instance the following macro expanding to ``multi-define``:
$$MULTI-DEFINE2
-The macro introduces a dummy identifier ``id2``.
+``multi-define2`` introduces a dummy identifier ``id2``.
Had we defined ``multi-define`` in terms of ``symbol-identifier=?``,
calling ``multi-define2`` with argument ``id`` equal to ``id2``
would have generated a spurious name clash. Fortunately, since we defined
@@ -132,9 +130,6 @@ would have generated a spurious name clash. Fortunately, since we defined
the identifier ``id2`` introduced by the macro has
different marks from the identifier ``id2`` coming as an argument.
-``free-identifier=?``
-------------------------------------
-
``bound-identifier=?`` is not good for every circumstance. Consider
for instance the following variation of ``multi-define``, featuring
a literal keyword ``as``:
@@ -161,22 +156,28 @@ an error even when the ``as`` identifiers are spelled correctly:
1. &who: multi-def-bad
2. &message: "Offending infix syntax (expected `as')"
3. &syntax:
- form: (as as)
+ form: as
subform: #f
+ 4. &trace: #<syntax as>
The reason is that ``as`` is not ``bound-identifier=?``
-to ``#'as``. We need a less strict comparison predicate such as
-``symbol-identifier=?`` or ``free-identifier=?``.
+to ``#'as``. We need a less strict comparison predicate.
+To this aim the Scheme standard provides another equality procedures
+for identifiers, ``free-identifier=?``, which however is not quite right.
+
+``free-identifier=?``
+-----------------------------------------
``free-identifier=?`` is
-the most complicated equality predicate. As
-usual, the name is misleading since the arguments of
+the most complicated equality predicate.
+I find its `description in the R6RS document`_ particularly confusing and
+the name is misleading since the arguments of
``free-identifier=?`` are not required to be free identifiers.
A better name would be ``lax-identifier=?``.
Two identifiers are ``free-identifier=?`` if
-1. they are both bound and they share the same name, or they shared
- the same name before renaming at import time;
+1. they are both bound to the same binding and they share the same name
+ (or they shared the same name before renaming at import time);
2. they are both unbound and they share the same name.
In implementations with full phase separation, the identifiers
@@ -195,14 +196,18 @@ Notice that both ``symbol-identifier=?`` and ``bound-identifier=?``
would fail to recognize the identity of ``range`` and ``r`` in this
case.
+It is important to know about ``free-identifier=?`` because
+in macros with literal identifiers the literal identifiers
+are compared by using it, internally. That explain a behavior
+which can be quite surprising.
+
.. _9: http://www.artima.com/weblogs/viewpost.jsp?thread=240804
+.. _description in the R6RS document: http://www.r6rs.org/final/html/r6rs-lib/r6rs-lib-Z-H-13.html#node_idx_1142
Literal identifiers and auxiliary syntax
-----------------------------------------------------
-Macros with literal identifiers may be surprising, because internally
-the literal identifiers are compared by using ``free-identifier=?``.
-Consider for instance the macro ``multi-def`` defined in the previous
+Consider the macro ``multi-def`` defined in the previous
paragraph. This works:
.. code-block:: scheme
@@ -227,24 +232,20 @@ But this does not work:
subform: #f
3. &trace: #<syntax (multi-def (x as 1) (y as 2))>
-The reason is that in the second example ``as`` is bound, and therefore
-it is not ``free-identifier=?`` to the literal identifier ``#'as``.
-
-The recommended "solution" is to define at top-level and to
-export some dummy definition for the literal identifiers you
-are going to use in your macro. I think this is fundamentally
-broken: literal identifiers should be a concept internal to
-the macro and they should not be exported. The mistake is
-that the R6RS requires the literal identifiers to be matched
-via ``free-identifier=?``, whereas they should be matched
-with ``symbol-identifier=?``. I never understood why the editors
-decided to use ``free-identifier=?``, perhaps because it makes it
-possible to rename the identifiers used as literal identifiers,
-a feature that looks more like a misfeature to me.
+That looks surprising, but it is not once you realize that internally
+literal identifiers are compared via ``free-identifier=?``.
+In the second example ``as`` is bound, and therefore
+it is not ``free-identifier=?`` to the literal identifier ``#'as``, which
+is unbound.
-Anyway, the R6RS document defines a set of special macros, such as
+The recommended "solution" is to introduce at top level some dummy definitions
+for the literal identifiers you are going to use in your macro, and to export
+them. Following this policy,
+the R6RS document defines a set of special macros,
``_``, ``...``, ``else`` and ``=>``, which lives in the global
-namespace and are available to all R6RS programs. Such macros are used
+namespace and are available to all R6RS programs.
+
+Such macros are used
as auxiliary syntax in various special forms, like ``cond`` and
``syntax-case``; for this reason they are usually called auxiliary
keywords. The existence of such global variables makes it impossible
@@ -258,6 +259,16 @@ using the auxiliary syntax:
(cond (else 'something)))
> ; does not return something
+I think this is fundamentally
+broken: literal identifiers should be a concept internal to
+the macro and they should not be exported. The mistake is
+that the R6RS requires the literal identifiers to be matched
+via ``free-identifier=?``, whereas they should be matched
+with ``symbol-identifier=?``. I never understood why the editors
+decided to use ``free-identifier=?``, perhaps because it makes it
+possible to rename the identifiers used as literal identifiers,
+a feature that looks of little utility to me. All in all, I think
+``free-identifier=?`` is another dark corner of R6RS Scheme.
|#
(import (rnrs) (sweet-macros) (aps compat)
@@ -300,24 +311,22 @@ using the auxiliary syntax:
(set! res (cons 'free= res)))
(datum->syntax #'compare-ids `',res)))
-(let ((a 1))
- (define id-a #'a)
- (let ((a a))
- (free-identifier=? #'a id-a)))
+;;MULTI-DEF
+;; not checking for duplicated identifiers here
+(define-syntax multi-def
+ (syntax-rules (as)
+ ((multi-def (name as value) ...)
+ (begin (define name value) ...))))
+;;END
;;MULTI-DEF-BAD
-(def-syntax (multi-def-bad (name as_ value) ...)
+(def-syntax (multi-def-bad (name as_ value) ...)
#'(begin (define name value) ...)
- (for-all (lambda (id) (bound-identifier=? id #'as)) #'(as_ ...))
- (syntax-violation 'multi-def-bad "Offending infix syntax (expected `as')"
- (remp (lambda (id) (bound-identifier=? id #'as)) #'(as_ ...))))
-;;END
-
-;;MULTI-DEF
- (define-syntax multi-def
- (syntax-rules (as)
- ((multi-def (name as value) ...)
- (begin (define name value) ...))))
+ (for-all (lambda (id)
+ (when (not (bound-identifier=? id #'as))
+ (syntax-violation
+ 'multi-def-bad "Offending infix syntax (expected `as')" id)))
+ #'(as_ ...)))
;;END
;;FREE-DISTINCT
@@ -339,13 +348,15 @@ using the auxiliary syntax:
(def-syntax (check-reserved id)
(syntax-violation 'check-reserved "Reserved identifier" #'id)
(exists (cut symbol-identifier=? #'id <>) (list #'reserved1 #'reserved2))
- #f)
+ 'non-reserved)
;;END
(def-syntax (distinct-x a)
#'(symbol-distinct x a))
(run
+
+ (test "reserved" (check-reserved a) #f)
(test "symbol1" (symbol-distinct a b) #t)
(test "symbol2" (symbol-distinct a a) #f)
diff --git a/artima/scheme/table-of-contents.txt b/artima/scheme/table-of-contents.txt
index 0369900..94cd1af 100644
--- a/artima/scheme/table-of-contents.txt
+++ b/artima/scheme/table-of-contents.txt
@@ -65,6 +65,10 @@ Part V - Macros, again
Ep28_ Hygienic macros
+ Ep29_ Breaking hygiene
+
+ Ep30_ Comparing identifiers
+
.. _Ep1: http://www.artima.com/weblogs/viewpost.jsp?thread=238789
.. _Ep2: http://www.artima.com/weblogs/viewpost.jsp?thread=238941
.. _Ep3: http://www.artima.com/weblogs/viewpost.jsp?thread=239466
@@ -93,3 +97,5 @@ Part V - Macros, again
.. _Ep26: http://www.artima.com/weblogs/viewpost.jsp?thread=259977
.. _Ep27: http://www.artima.com/weblogs/viewpost.jsp?thread=260182
.. _Ep28: http://www.artima.com/weblogs/viewpost.jsp?thread=260195
+.. _Ep29: http://www.artima.com/weblogs/viewpost.jsp?thread=261363
+.. _Ep30: http://www.artima.com/weblogs/viewpost.jsp?thread=261364