Add some docs for gensym and siblings

This commit is contained in:
Bob Tolbert 2013-12-30 14:42:55 -07:00
parent f189f0a457
commit 4e3b6fd4cf
2 changed files with 162 additions and 6 deletions

View File

@ -357,6 +357,8 @@ Parameters may have following keywords in front of them:
=> (zig-zag-sum 1 2 3 4 5 6) => (zig-zag-sum 1 2 3 4 5 6)
-3 -3
.. _defmacro:
defmacro defmacro
-------- --------
@ -378,6 +380,24 @@ between the operands.
=> (infix (1 + 1)) => (infix (1 + 1))
2 2
.. _defmacro/g!:
defmacro/g!
------------
.. versionadded:: 0.9.12
`defmacro/g!` is a special version of `defmacro` that is used to
automatically generate :ref:`gensym` for any symbol that
starts with ``g!``.
So ``g!a`` would become ``(gensym "a")``.
.. seealso::
Section :ref:`using-gensym`
del del
--- ---
@ -494,6 +514,28 @@ normally. If the execution is halted with `break`, the `else` does not execute.
loop finished loop finished
.. _gensym:
gensym
------
.. versionadded:: 0.9.12
`gensym` form is used to generate a unique symbol to allow writing macros
without accidental variable name clashes.
.. code-block:: clj
=> (gensym)
u':G_1235'
=> (gensym "x")
u':x_1236'
.. seealso::
Section :ref:`using-gensym`
get get
--- ---
@ -983,6 +1025,35 @@ values that are incremented by 1. When decorated `addition` is called with value
4 4
.. _with-gensyms:
with-gensyms
-------------
.. versionadded:: 0.9.12
`with-gensym` form is used to generate a set of :ref:`gensym` for use
in a macro.
.. code-block:: clojure
(with-gensyms [a b c]
...)
expands to:
.. code-block:: clojure
(let [[a (gensym)
[b (gensym)
[c (gensym)]]
...)
.. seealso::
Section :ref:`using-gensym`
yield yield
----- -----

View File

@ -2,26 +2,111 @@
Internal Hy Documentation Internal Hy Documentation
========================= =========================
.. info:: .. note::
These bits are for folks who hack on Hy it's self, mostly! These bits are for folks who hack on Hy itself, mostly!
Hy Models Hy Models
========= =========
.. TODO:: .. todo::
Write this. Write this.
Hy Macros Hy Macros
========= =========
.. TODO:: .. _using-gensym:
Write this.
Using gensym for safer macros
------------------------------
When writing macros, one must be careful to avoid capturing external variables
or using variable names that might conflict with user code.
We will use an example macro ``nif`` (see http://letoverlambda.com/index.cl/guest/chap3.html#sec_5
for a more complete description.) ``nif`` is an example, something like a numeric ``if``,
where based on the expression, one of the 3 forms is called depending on if the
expression is positive, zero or negative.
A first pass might be someting like:
.. code-block:: clojure
(defmacro nif [expr pos-form zero-form neg-form]
`(let [[obscure-name ~expr]]
(cond [(pos? obscure-name) ~pos-form]
[(zero? obscure-name) ~zero-form]
[(neg? obscure-name) ~neg-form])))
where ``obsure-name`` is an attempt to pick some variable name as not to
conflict with other code. But of course, while well-intentioned,
this is no guarantee.
The method :ref:`gensym` is designed to generate a new, unique symbol for just
such an occasion. A much better version of ``nif`` would be:
.. code-block:: clojure
(defmacro nif [expr pos-form zero-form neg-form]
(let [[g (gensym)]]
`(let [[~g ~expr]]
(cond [(pos? ~g) ~pos-form]
[(zero? ~g) ~zero-form]
[(neg? ~g) ~neg-form]))))
This is an easy case, since there is only one symbol. But if there is
a need for several gensym's there is a second macro :ref:`with-gensyms` that
basically expands to a series of ``let`` statements:
.. code-block:: clojure
(with-gensyms [a b c]
...)
expands to:
.. code-block:: clojure
(let [[a (gensym)
[b (gensym)
[c (gensym)]]
...)
so our re-written ``nif`` would look like:
.. code-block:: clojure
(defmacro nif [expr pos-form zero-form neg-form]
(with-gensyms [g]
`(let [[~g ~expr]]
(cond [(pos? ~g) ~pos-form]
[(zero? ~g) ~zero-form]
[(neg? ~g) ~neg-form]))))
Finally, though we can make a new macro that does all this for us. :ref:`defmacro/g!`
will take all symbols that begin with ``g!`` and automatically call ``gensym`` with the
remainder of the symbol. So ``g!a`` would become ``(gensym "a")``.
Our final version of ``nif``, built with ``defmacro/g!`` becomes:
.. code-block:: clojure
(defmacro/g! nif [expr pos-form zero-form neg-form]
`(let [[~g!res ~expr]]
(cond [(pos? ~g!res) ~pos-form]
[(zero? ~g!res) ~zero-form]
[(neg? ~g!res) ~neg-form]))))
Checking macro arguments and raising exceptions
-----------------------------------------------
Hy Compiler Builtins Hy Compiler Builtins
==================== ====================
.. TODO:: .. todo::
Write this. Write this.