Add some docs for gensym and siblings
This commit is contained in:
parent
f189f0a457
commit
4e3b6fd4cf
@ -357,6 +357,8 @@ Parameters may have following keywords in front of them:
|
||||
=> (zig-zag-sum 1 2 3 4 5 6)
|
||||
-3
|
||||
|
||||
.. _defmacro:
|
||||
|
||||
defmacro
|
||||
--------
|
||||
|
||||
@ -378,6 +380,24 @@ between the operands.
|
||||
=> (infix (1 + 1))
|
||||
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
|
||||
---
|
||||
|
||||
@ -494,6 +514,28 @@ normally. If the execution is halted with `break`, the `else` does not execute.
|
||||
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
|
||||
---
|
||||
|
||||
@ -983,6 +1025,35 @@ values that are incremented by 1. When decorated `addition` is called with value
|
||||
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
|
||||
-----
|
||||
|
||||
|
@ -2,26 +2,111 @@
|
||||
Internal Hy Documentation
|
||||
=========================
|
||||
|
||||
.. info::
|
||||
These bits are for folks who hack on Hy it's self, mostly!
|
||||
.. note::
|
||||
These bits are for folks who hack on Hy itself, mostly!
|
||||
|
||||
|
||||
Hy Models
|
||||
=========
|
||||
|
||||
.. TODO::
|
||||
.. todo::
|
||||
Write this.
|
||||
|
||||
|
||||
Hy Macros
|
||||
=========
|
||||
|
||||
.. TODO::
|
||||
Write this.
|
||||
.. _using-gensym:
|
||||
|
||||
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
|
||||
====================
|
||||
|
||||
.. TODO::
|
||||
.. todo::
|
||||
Write this.
|
||||
|
Loading…
Reference in New Issue
Block a user