2013-12-25 20:18:09 +01:00
|
|
|
================
|
2013-11-30 01:59:20 +01:00
|
|
|
Anaphoric Macros
|
2013-12-25 20:18:09 +01:00
|
|
|
================
|
|
|
|
|
|
|
|
.. versionadded:: 0.9.12
|
2013-11-30 01:59:20 +01:00
|
|
|
|
|
|
|
The anaphoric macros module makes functional programming in Hy very
|
|
|
|
concise and easy to read.
|
|
|
|
|
|
|
|
An anaphoric macro is a type of programming macro that
|
|
|
|
deliberately captures some form supplied to the macro which may be
|
|
|
|
referred to by an anaphor (an expression referring to another).
|
|
|
|
|
2016-09-04 22:35:46 +02:00
|
|
|
-- Wikipedia (https://en.wikipedia.org/wiki/Anaphoric_macro)
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2016-12-26 23:44:59 +01:00
|
|
|
To use these macros you need to require the ``hy.extra.anaphoric`` module like so:
|
2015-10-16 20:28:30 +02:00
|
|
|
|
2016-12-26 23:44:59 +01:00
|
|
|
``(require [hy.extra.anaphoric [*]])``
|
2013-12-26 02:28:32 +01:00
|
|
|
|
2019-12-21 19:26:37 +01:00
|
|
|
These macros are implemented by replacing any use of the designated
|
|
|
|
anaphoric symbols (``it``, in most cases) with a gensym. Consequently,
|
2020-03-28 23:48:16 +01:00
|
|
|
it's unwise to nest these macros where symbol replacement is happening.
|
|
|
|
Symbol replacement typically takes place in ``body`` or ``form``
|
|
|
|
parameters, where the output of the expression may be returned. It is also
|
|
|
|
recommended to avoid using an affected symbol as something other than a
|
|
|
|
variable name, as in ``(print "My favorite Stephen King book is" 'it)``.
|
2019-12-21 19:26:37 +01:00
|
|
|
|
2013-12-26 02:28:32 +01:00
|
|
|
.. _ap-if:
|
|
|
|
|
|
|
|
ap-if
|
2015-08-12 02:11:33 +02:00
|
|
|
=====
|
2013-12-26 02:28:32 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-if test-form then-form else-form)``
|
2013-12-26 02:28:32 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
As :ref:`if <if>`, but the result of the test form is named ``it`` in
|
|
|
|
the subsequent forms. As with ``if``, the else-clause is optional.
|
|
|
|
|
|
|
|
.. code-block:: hy
|
|
|
|
|
|
|
|
=> (import os)
|
|
|
|
=> (ap-if (.get os.environ "PYTHONPATH")
|
|
|
|
... (print "Your PYTHONPATH is" it))
|
2013-12-26 02:28:32 +01:00
|
|
|
|
|
|
|
|
2013-11-30 01:59:20 +01:00
|
|
|
.. _ap-each:
|
|
|
|
|
|
|
|
ap-each
|
2015-08-12 02:11:33 +02:00
|
|
|
=======
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-each xs body…)``
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Evaluate the body forms for each element ``it`` of ``xs`` and return
|
|
|
|
``None``.
|
|
|
|
|
|
|
|
.. code-block:: hy
|
|
|
|
|
|
|
|
=> (ap-each [1 2 3] (print it))
|
|
|
|
1
|
|
|
|
2
|
|
|
|
3
|
2013-11-30 01:59:20 +01:00
|
|
|
|
|
|
|
|
|
|
|
.. _ap-each-while:
|
|
|
|
|
|
|
|
ap-each-while
|
|
|
|
=============
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-each-while xs pred body…)``
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
As ``ap-each``, but the form ``pred`` is run before the body forms on
|
|
|
|
each iteration, and the loop ends if ``pred`` is false.
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-11-30 01:59:20 +01:00
|
|
|
|
|
|
|
=> (ap-each-while [1 2 3 4 5 6] (< it 4) (print it))
|
|
|
|
1
|
|
|
|
2
|
|
|
|
3
|
|
|
|
|
|
|
|
.. _ap-map:
|
|
|
|
|
|
|
|
ap-map
|
|
|
|
======
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-map form xs)``
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Create a generator like :py:func:`map` that yields each result of ``form``
|
|
|
|
evaluated with ``it`` bound to successive elements of ``xs``.
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-11-30 01:59:20 +01:00
|
|
|
|
|
|
|
=> (list (ap-map (* it 2) [1 2 3]))
|
|
|
|
[2, 4, 6]
|
|
|
|
|
|
|
|
|
|
|
|
.. _ap-map-when:
|
|
|
|
|
|
|
|
ap-map-when
|
|
|
|
===========
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-map-when predfn rep xs)``
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
As ``ap-map``, but the predicate function ``predfn`` (yes, that's a
|
|
|
|
function, not an anaphoric form) is applied to each ``it``, and the
|
|
|
|
anaphoric mapping form ``rep`` is only applied if the predicate is true.
|
|
|
|
Otherwise, ``it`` is yielded unchanged.
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-11-30 01:59:20 +01:00
|
|
|
|
|
|
|
=> (list (ap-map-when odd? (* it 2) [1 2 3 4]))
|
|
|
|
[2, 2, 6, 4]
|
|
|
|
|
|
|
|
=> (list (ap-map-when even? (* it 2) [1 2 3 4]))
|
|
|
|
[1, 4, 3, 8]
|
|
|
|
|
|
|
|
|
|
|
|
.. _ap-filter:
|
|
|
|
|
|
|
|
ap-filter
|
|
|
|
=========
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-filter form xs)``
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
The :py:func:`filter` equivalent of ``ap-map``.
|
2013-11-30 01:59:20 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-11-30 01:59:20 +01:00
|
|
|
|
|
|
|
=> (list (ap-filter (> (* it 2) 6) [1 2 3 4 5]))
|
|
|
|
[4, 5]
|
|
|
|
|
|
|
|
|
2013-12-25 20:18:09 +01:00
|
|
|
.. _ap-reject:
|
|
|
|
|
|
|
|
ap-reject
|
|
|
|
=========
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-reject form xs)``
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Equivalent to ``(ap-filter (not form) xs)``.
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-12-25 20:18:09 +01:00
|
|
|
|
|
|
|
=> (list (ap-reject (> (* it 2) 6) [1 2 3 4 5]))
|
|
|
|
[1, 2, 3]
|
|
|
|
|
|
|
|
|
|
|
|
.. _ap-dotimes:
|
|
|
|
|
|
|
|
ap-dotimes
|
|
|
|
==========
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-dotimes n body…)``
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Equivalent to ``(ap-each (range n) body…)``.
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-12-25 20:18:09 +01:00
|
|
|
|
|
|
|
=> (setv n [])
|
|
|
|
=> (ap-dotimes 3 (.append n it))
|
|
|
|
=> n
|
|
|
|
[0, 1, 2]
|
|
|
|
|
|
|
|
|
|
|
|
.. _ap-first:
|
|
|
|
|
|
|
|
ap-first
|
|
|
|
========
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-first form xs)``
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Evaluate the predicate ``form`` for each element ``it`` of ``xs``. When
|
|
|
|
the predicate is true, stop and return ``it``. If the predicate is never
|
|
|
|
true, return ``None``.
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
=> (ap-first (> it 5) (range 10))
|
2013-12-25 20:18:09 +01:00
|
|
|
6
|
|
|
|
|
|
|
|
|
|
|
|
.. _ap-last:
|
|
|
|
|
|
|
|
ap-last
|
|
|
|
========
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-last form list)``
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Evaluate the predicate ``form`` for every element ``it`` of ``xs``.
|
|
|
|
Return the last element for which the predicate is true, or ``None`` if
|
|
|
|
there is no such element.
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
=> (ap-last (> it 5) (range 10))
|
2013-12-25 20:18:09 +01:00
|
|
|
9
|
|
|
|
|
|
|
|
|
|
|
|
.. _ap-reduce:
|
|
|
|
|
|
|
|
ap-reduce
|
|
|
|
=========
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``(ap-reduce form xs &optional initial-value)``
|
|
|
|
|
|
|
|
This macro is an anaphoric version of :py:func:`reduce`. It works as
|
|
|
|
follows:
|
|
|
|
|
|
|
|
- Bind ``acc`` to the first element of ``xs``, bind ``it`` to the
|
|
|
|
second, and evaluate ``form``.
|
|
|
|
- Bind ``acc`` to the result, bind ``it`` to the third value of ``xs``,
|
|
|
|
and evaluate ``form`` again.
|
|
|
|
- Bind ``acc`` to the result, and continue until ``xs`` is exhausted.
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
If ``initial-value`` is supplied, the process instead begins with
|
|
|
|
``acc`` set to ``initial-value`` and ``it`` set to the first element of
|
|
|
|
``xs``.
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2014-03-14 14:01:47 +01:00
|
|
|
.. code-block:: hy
|
2013-12-25 20:18:09 +01:00
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
=> (ap-reduce (+ it acc) (range 10))
|
2013-12-25 20:18:09 +01:00
|
|
|
45
|
2015-04-26 18:35:46 +02:00
|
|
|
|
|
|
|
|
2017-10-23 03:53:05 +02:00
|
|
|
.. _#%
|
2015-08-12 02:11:33 +02:00
|
|
|
|
2017-10-23 03:53:05 +02:00
|
|
|
#%
|
2015-08-12 02:11:33 +02:00
|
|
|
==
|
|
|
|
|
2019-12-21 20:30:53 +01:00
|
|
|
Usage: ``#% expr``
|
2015-08-12 02:11:33 +02:00
|
|
|
|
2017-10-26 04:46:38 +02:00
|
|
|
Makes an expression into a function with an implicit ``%`` parameter list.
|
2017-10-23 05:36:30 +02:00
|
|
|
|
2017-10-26 04:46:38 +02:00
|
|
|
A ``%i`` symbol designates the (1-based) *i* th parameter (such as ``%3``).
|
|
|
|
Only the maximum ``%i`` determines the number of ``%i`` parameters--the
|
|
|
|
others need not appear in the expression.
|
2017-10-23 05:36:30 +02:00
|
|
|
``%*`` and ``%**`` name the ``&rest`` and ``&kwargs`` parameters, respectively.
|
2015-08-12 02:11:33 +02:00
|
|
|
|
2017-10-26 04:46:38 +02:00
|
|
|
.. code-block:: hy
|
|
|
|
|
|
|
|
=> (#%[%1 %6 42 [%2 %3] %* %4] 1 2 3 4 555 6 7 8)
|
|
|
|
[1, 6, 42, [2, 3], (7, 8), 4]
|
|
|
|
=> (#% %** :foo 2)
|
|
|
|
{"foo": 2}
|
|
|
|
|
|
|
|
When used on an s-expression,
|
|
|
|
``#%`` is similar to Clojure's anonymous function literals--``#()``.
|
2015-08-12 02:11:33 +02:00
|
|
|
|
|
|
|
.. code-block:: hy
|
|
|
|
|
2017-10-26 04:46:38 +02:00
|
|
|
=> (setv add-10 #%(+ 10 %1))
|
|
|
|
=> (add-10 6)
|
|
|
|
16
|
|
|
|
|
|
|
|
``#%`` determines the parameter list by the presence of a ``%*`` or ``%**``
|
|
|
|
symbol and by the maximum ``%i`` symbol found *anywhere* in the expression,
|
|
|
|
so nesting of ``#%`` forms is not recommended.
|
|
|
|
|