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, or to use an affected symbol as something other than a variable name, as in (print "My favorite Stephen King book is" 'it)
.
Usage: (ap-if test-form then-form else-form)
As if <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))
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
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
Usage: (ap-map form xs)
Create a generator like :pymap
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]
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]
Usage: (ap-filter form xs)
The :pyfilter
equivalent of ap-map
.
=> (list (ap-filter (> (* it 2) 6) [1 2 3 4 5]))
[4, 5]
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]
Usage: (ap-dotimes n body…)
Equivalent to (ap-each (range n) body…)
.
=> (setv n [])
=> (ap-dotimes 3 (.append n it))
=> n
[0, 1, 2]
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
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
Usage: (ap-reduce form xs &optional initial-value)
This macro is an anaphoric version of :pyreduce
. 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.