Anaphoric Macros¶
New in version 0.9.12.
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).
—Wikipedia (https://en.wikipedia.org/wiki/Anaphoric_macro)
To use these macros you need to require the hy.extra.anaphoric
module like so:
(require [hy.extra.anaphoric [*]])
These macros are implemented by replacing any use of the designated
anaphoric symbols (it
, in most cases) with a gensym. Consequently,
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)
.
ap-if¶
Usage: (ap-if test-form then-form else-form)
As if, but the result of the test form is named it
in
the subsequent forms. As with if
, the else-clause is optional.
=> (import os)
=> (ap-if (.get os.environ "PYTHONPATH")
... (print "Your PYTHONPATH is" it))
ap-each¶
Usage: (ap-each xs body…)
Evaluate the body forms for each element it
of xs
and return
None
.
=> (ap-each [1 2 3] (print it))
1
2
3
ap-each-while¶
Usage: (ap-each-while xs pred body…)
As ap-each
, but the form pred
is run before the body forms on
each iteration, and the loop ends if pred
is false.
=> (ap-each-while [1 2 3 4 5 6] (< it 4) (print it))
1
2
3
ap-map¶
Usage: (ap-map form xs)
Create a generator like map()
that yields each result of form
evaluated with it
bound to successive elements of xs
.
=> (list (ap-map (* it 2) [1 2 3]))
[2, 4, 6]
ap-map-when¶
Usage: (ap-map-when predfn rep xs)
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.
=> (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¶
Usage: (ap-filter form xs)
The filter()
equivalent of ap-map
.
=> (list (ap-filter (> (* it 2) 6) [1 2 3 4 5]))
[4, 5]
ap-reject¶
Usage: (ap-reject form xs)
Equivalent to (ap-filter (not form) xs)
.
=> (list (ap-reject (> (* it 2) 6) [1 2 3 4 5]))
[1, 2, 3]
ap-dotimes¶
Usage: (ap-dotimes n body…)
Equivalent to (ap-each (range n) body…)
.
=> (setv n [])
=> (ap-dotimes 3 (.append n it))
=> n
[0, 1, 2]
ap-first¶
Usage: (ap-first form xs)
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
.
=> (ap-first (> it 5) (range 10))
6
ap-last¶
Usage: (ap-last form list)
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.
=> (ap-last (> it 5) (range 10))
9
ap-reduce¶
Usage: (ap-reduce form xs &optional initial-value)
This macro is an anaphoric version of reduce()
. It works as
follows:
- Bind
acc
to the first element ofxs
, bindit
to the second, and evaluateform
. - Bind
acc
to the result, bindit
to the third value ofxs
, and evaluateform
again. - Bind
acc
to the result, and continue untilxs
is exhausted.
If initial-value
is supplied, the process instead begins with
acc
set to initial-value
and it
set to the first element of
xs
.
=> (ap-reduce (+ it acc) (range 10))
45
#%¶
Usage: #% expr
Makes an expression into a function with an implicit %
parameter list.
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.
%*
and %**
name the &rest
and &kwargs
parameters, respectively.
=> (#%[%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–#()
.
=> (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.