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)
|
=> (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
|
||||||
-----
|
-----
|
||||||
|
|
||||||
|
@ -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.
|
||||||
|
Loading…
Reference in New Issue
Block a user