summaryrefslogtreecommitdiff
path: root/artima
diff options
context:
space:
mode:
authormichele.simionato <devnull@localhost>2009-05-19 05:06:17 +0000
committermichele.simionato <devnull@localhost>2009-05-19 05:06:17 +0000
commit39ad55da678aba3d62b1f1810a2352bccf33a6cb (patch)
treece66d2a7601515a01df39f3d5f5727a2584b733c /artima
parentba5ebf54417aae9d796e1cbf34e123ea36c333ae (diff)
downloadmicheles-39ad55da678aba3d62b1f1810a2352bccf33a6cb.tar.gz
Published version of scheme23
Diffstat (limited to 'artima')
-rw-r--r--artima/scheme/scheme23.ss106
1 files changed, 56 insertions, 50 deletions
diff --git a/artima/scheme/scheme23.ss b/artima/scheme/scheme23.ss
index cb4fc6d..90e09f3 100644
--- a/artima/scheme/scheme23.ss
+++ b/artima/scheme/scheme23.ss
@@ -5,29 +5,27 @@
.. _You want it when?: http://www.cs.utah.edu/plt/publications/macromod.pdf
.. _SRFI-19: http://srfi.schemers.org/srfi-19/srfi-19.html
-Scheme is all about times:
-there is a run-time, an expand-time, and in general a
+Scheme is all about times: there is a run-time, an expand-time, and a
discrete set of times associated to the meta-levels. When
-using separate compilation there is another set of times to take in
-consideration: the times when the libraries are separately compiled.
-If the separately compiled libraries define
-macros which used in client code, there is yet another sets of times
-to take in consideration, the *visit times*.
+separate compilation is taken in consideration, there is also another set
+of times: the times when the libraries are separately compiled.
+Finally, if the separately compiled libraries define macros which are used
+in client code, there is yet another set of times, the *visit times*.
.. image:: time.jpg
-Suppose we have a low level library ``L``, compiled yesterday,
-defining a macro we want to use in another middle level library ``M``,
-to be compiled today. The middle level library needs to know about the
-macro definition at the time of its compilation, because it has to
-expand code. Therefore, the compiler must look at the low level
-library and re-evaluate the macro definition today (this process is
-called *visiting*). The visit time is different from the time of the
-compilation of ``L`` as it happens just before the compilation of
-``M``. The example below should make things clear.
+To explain what the visit time is, suppose you have a low level
+library ``L``, compiled yesterday, defining a macro you want to use in
+another middle level library ``M``, to be compiled today. The compiler
+needs to know about the macro defined in ``L`` at the time of the
+compilation of ``M``, because it has to expand code in
+``M``. Therefore, the compiler must look at ``L`` and re-evaluate the
+macro definition today (the process is called *visiting*). The visit
+time is different from the time of the compilation of ``L`` as it
+happens just before the compilation of ``M``.
-Consider the following low level library ``L``, defining a macro ``m``
-and an integer variable ``a``:
+Here is a concrete example. Consider the following low level library
+``L``, defining a macro ``m`` and an integer variable ``a``:
$$experimental/L:
@@ -40,7 +38,7 @@ You may compile it with PLT Scheme::
Since the right hand side of a macro definition is evaluated at
compile time the message ``visiting L`` is printed during compilation,
as expected.
-Consider now the following simple middle level library using the macro ``m``:
+Consider now the following middle level library ``M`` using the macro ``m``:
$$experimental/M:
@@ -51,7 +49,7 @@ to compile ``M``. This is actually what happens::
[Compiling /usr/home/micheles/gcode/scheme/experimental/M.sls]
visiting L
-If you comment out the line with the macro call, the compiler in principle
+If you comment out the line with the macro call, the compiler
does not need to visit ``L`` anymore; some implementations may take
advantage of this fact (Ypsilon and Ikarus do). However, PLT Scheme will
continue to visit ``L`` in any case.
@@ -62,25 +60,26 @@ The mysterious import semantics
It is time to ask ourselves the crucial question:
what does it mean to *import* a library?
-For a Pythonista, things are simple: importing a library means
-executing it at run-time. For a Schemer, things are complicated:
-importing a library implies that some operation are performed at
+For a Pythonista, things are very simple: importing a library means
+executing it at run-time. For a Schemer, things are somewhat complicated:
+importing a library implies that some basic operations are performed at
compile time - such as looking at the exported identifiers and at the
dependencies of the library - but there is also a lot of unspecified
behavior which may happen both a compile-time and at run-time.
-In particular at compile time a library may be only visited,
+In particular at compile-time a library may be only visited,
i.e. its macro definitions can be re-evaluated - or can be
only instantiated, or both. Different things happens in different
situations and in the same situation different implementations
can perform different operations.
-The example of the previous paragraph if very useful to
-have an idea of what is portable behavior and what is not.
+The example of the previous paragraph is useful in order to get a feeling
+of what is portable behavior and what is not.
Let me first consider what happens in Ikarus.
If I want to compile ``L`` and ``M`` in Ikarus, I need to introduce
a helper script ``H.ss``, since Ikarus has no direct way to compile
-a library from the command line:
+a library from the command line. Here is the script::
+ $ cat H.ss
$$experimental/H:
Here is what I get::
@@ -92,12 +91,16 @@ Here is what I get::
Ikarus is lazier than PLT: for instance, if you comment the
line invoking the macro in ``M.sls`` and you recompile the dependencies,
-then the library ``M`` is not visited. You may
-also check that if you introduce a dummy macro in ``M``, depending on
-the variable ``a`` defined in ``L`` (for instance if you add a line
-``(def-syntax dummy (lambda (x) a))``) then the library ``L``
-needs to be instantiated just to compile ``M``.
+then the library ``M`` is not visited.
+Both PLT and Ikarus do not instantiate ``L`` in order to compile
+``M`` (it is not needed) but Ypsilon does. You may check that if you
+introduce a dummy macro in ``M``, depending on the variable ``a``
+defined in ``L`` (for instance if you add a line ``(def-syntax
+dummy (lambda (x) a))``) then the library ``L`` must be instantiated
+in order to compile ``M``, and all implementations do so.
+
+Let us consider the peculiarities of Ypsilon, now.
Ypsilon does not have a switch to compile a library without
executing it - even if this is possible by invoking the low level
compiler API - so we must execute ``H.ss`` to compile its dependencies::
@@ -126,7 +129,7 @@ and the output of PLT::
M instantiated
42
-The first thing to notice is that in Ikarus and in PLT we relied on the
+The first thing to notice is that both in Ikarus and in PLT we relied on the
fact that the libraries were precompiled, so in order to perform a fair
comparison we must run Ypsilon again (this second time the libraries
L and M will be precompiled)::
@@ -144,7 +147,7 @@ the helper script ``H`` does not use any macro so it does not really need
to visit ``L`` or ``M`` to be compiled. The same happens for Ikarus.
PLT instead visits ``L`` twice
to compile ``H.ss``. In PLT all dependencies (both direct and indirect)
-are always visited when compiling. If we compile
+are always visited when compiling. Only if we compile
the script once and for all
::
@@ -155,32 +158,35 @@ the script once and for all
visiting L
visiting L
-obviously the ``visiting L`` message will not be printed::
+the ``visiting L`` message will not be printed::
$ plt-r6rs H.ss
L instantiated
M instantiated
42
-Portability gotchas
+More implementation-dependent details
---------------------------------------------------------
Having performed the right number of compilations now
the output of PLT and Ypsilon are the same; nevertheless, the output of
Ikarus is different, since Ikarus does not instantiate the middle level
-library ``M``. The reason is the implicit phasing semantics of Ikarus
+library ``M``. The reason is the *implicit phasing* semantics of Ikarus
(other implementations based on psyntax would exhibit the same behavior): the
helper script ``H.ss`` is printing the variable ``a`` which really
comes from the library ``L``. Ikarus is clever enough to recognize this
-fact and lazy enough to avoid instantiating the ``M`` library without
-need. On the other hand, Ypsilon performs eager instantiation and it
+fact and lazy enough to avoid instantiating ``M`` without
+need.
+
+On the other hand, Ypsilon performs eager instantiation and it
instantiates (once) all the libraries it imports
(both directly and indirectly), even at compile time and even in situations
when the instantiation would not be needed for compilation of the client
-library.
+library. As you see, Scheme implementations have a lot of latitude in
+such matters.
The implementations based on psyntax are the smartest out there, but
-begin smart is not the same as being good.
+begin smart is not always the same thing as being good.
It is good to avoid instantiating a library if the instantiation is
really unneeded; it is bad if the library has some side effect, since
the side effect will mysteriously disappear. In our example the side
@@ -204,15 +210,15 @@ You may do so as follows:
...
)
-The library here does not export anything, since it relies on side effects
-to populate the global registry of functions; the idea is to access the
-functions later, with a call of kind ``(registry-ref <func-name>)``.
-This design as it is is not portable to systems based on psyntax, because
-such systems will not instantiate the library (the library does not export
-any variable, nothing of the library can be used in client code!).
-This can easily be fixed, by introducing an initialization function
-to be exported and called explicitly from client code, which is a
-good idea in any case.
+The library here does not export anything, since it relies on side
+effects to populate the global registry of functions; the idea is to
+access the functions later, with a call of kind ``(registry-ref
+<func-name>)``. This design as it is is not always portable to
+systems based on psyntax, because such systems will not instantiate
+the library (the library does not export any variable, nothing of the
+library can be used in client code!). This can easily be fixed, by
+introducing an initialization function to be exported and called
+explicitly from client code, which is a good idea in any case.
Analogously, a library based on side effects at visit time,
i.e. in the right hand side of macro definitions, is not portable,