Use a gensym for it
in anaphoric macros
This commit is contained in:
parent
bafd919605
commit
e57bbb92db
@ -17,6 +17,12 @@ To use these macros you need to require the ``hy.extra.anaphoric`` module like s
|
|||||||
|
|
||||||
``(require [hy.extra.anaphoric [*]])``
|
``(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)``.
|
||||||
|
|
||||||
.. _ap-if:
|
.. _ap-if:
|
||||||
|
|
||||||
ap-if
|
ap-if
|
||||||
|
@ -6,72 +6,72 @@
|
|||||||
;;; These macros make writing functional programs more concise
|
;;; These macros make writing functional programs more concise
|
||||||
|
|
||||||
(defmacro ap-if [test-form then-form &optional else-form]
|
(defmacro ap-if [test-form then-form &optional else-form]
|
||||||
`(do
|
(rit `(do
|
||||||
(setv it ~test-form)
|
(setv it ~test-form)
|
||||||
(if it ~then-form ~else-form)))
|
(if it ~then-form ~else-form))))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-each [lst &rest body]
|
(defmacro ap-each [lst &rest body]
|
||||||
"Evaluate the body form for each element in the list."
|
"Evaluate the body form for each element in the list."
|
||||||
`(for [it ~lst] ~@body))
|
(rit `(for [it ~lst] ~@body)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-each-while [lst form &rest body]
|
(defmacro ap-each-while [lst form &rest body]
|
||||||
"Evaluate the body form for each element in the list while the
|
"Evaluate the body form for each element in the list while the
|
||||||
predicate form evaluates to True."
|
predicate form evaluates to True."
|
||||||
`(for [it ~lst]
|
(rit `(for [it ~lst]
|
||||||
(unless ~form
|
(unless ~form
|
||||||
(break))
|
(break))
|
||||||
~@body))
|
~@body)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-map [form lst]
|
(defmacro ap-map [form lst]
|
||||||
"Yield elements evaluated in the form for each element in the list."
|
"Yield elements evaluated in the form for each element in the list."
|
||||||
`(gfor it ~lst ~form))
|
(rit `(gfor it ~lst ~form)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-map-when [predfn rep lst]
|
(defmacro ap-map-when [predfn rep lst]
|
||||||
"Yield elements evaluated for each element in the list when the
|
"Yield elements evaluated for each element in the list when the
|
||||||
predicate function returns True."
|
predicate function returns True."
|
||||||
`(gfor it ~lst (if (~predfn it) ~rep it)))
|
(rit `(gfor it ~lst (if (~predfn it) ~rep it))))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-filter [form lst]
|
(defmacro ap-filter [form lst]
|
||||||
"Yield elements returned when the predicate form evaluates to True."
|
"Yield elements returned when the predicate form evaluates to True."
|
||||||
`(gfor it ~lst :if ~form it))
|
(rit `(gfor it ~lst :if ~form it)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-reject [form lst]
|
(defmacro ap-reject [form lst]
|
||||||
"Yield elements returned when the predicate form evaluates to False"
|
"Yield elements returned when the predicate form evaluates to False"
|
||||||
`(gfor it ~lst :if (not ~form) it))
|
(rit `(gfor it ~lst :if (not ~form) it)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-dotimes [n &rest body]
|
(defmacro ap-dotimes [n &rest body]
|
||||||
"Execute body for side effects `n' times, with it bound from 0 to n-1"
|
"Execute body for side effects `n' times, with it bound from 0 to n-1"
|
||||||
`(for [it (range ~n)]
|
(rit `(for [it (range ~n)]
|
||||||
~@body))
|
~@body)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-first [predfn lst]
|
(defmacro ap-first [predfn lst]
|
||||||
"Yield the first element that passes `predfn`"
|
"Yield the first element that passes `predfn`"
|
||||||
`(next
|
(rit `(next
|
||||||
(gfor it ~lst :if ~predfn it)
|
(gfor it ~lst :if ~predfn it)
|
||||||
None))
|
None)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro ap-last [predfn lst]
|
(defmacro ap-last [predfn lst]
|
||||||
"Yield the last element that passes `predfn`"
|
"Yield the last element that passes `predfn`"
|
||||||
(setv x (gensym))
|
(setv x (gensym))
|
||||||
`(do
|
(rit `(do
|
||||||
(setv ~x None)
|
(setv ~x None)
|
||||||
(for [it ~lst :if ~predfn]
|
(for [it ~lst :if ~predfn]
|
||||||
(setv ~x it))
|
(setv ~x it))
|
||||||
~x))
|
~x)))
|
||||||
|
|
||||||
|
|
||||||
(defmacro! ap-reduce [form o!lst &optional [initial-value None]]
|
(defmacro! ap-reduce [form o!lst &optional [initial-value None]]
|
||||||
"Anaphoric form of reduce, `acc' and `it' can be used for a form"
|
"Anaphoric form of reduce, `acc' and `it' can be used for a form"
|
||||||
`(do
|
(recur-sym-replace {'it (gensym) 'acc (gensym)} `(do
|
||||||
(setv acc ~(if (none? initial-value)
|
(setv acc ~(if (none? initial-value)
|
||||||
`(do
|
`(do
|
||||||
(setv ~g!lst (iter ~g!lst))
|
(setv ~g!lst (iter ~g!lst))
|
||||||
@ -79,7 +79,7 @@
|
|||||||
initial-value))
|
initial-value))
|
||||||
(for [it ~g!lst]
|
(for [it ~g!lst]
|
||||||
(setv acc ~form))
|
(setv acc ~form))
|
||||||
acc))
|
acc)))
|
||||||
|
|
||||||
|
|
||||||
(deftag % [expr]
|
(deftag % [expr]
|
||||||
@ -111,3 +111,23 @@
|
|||||||
'(&kwargs %**))]
|
'(&kwargs %**))]
|
||||||
~expr))
|
~expr))
|
||||||
|
|
||||||
|
|
||||||
|
;;; --------------------------------------------------
|
||||||
|
;;; Subroutines
|
||||||
|
;;; --------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
(defn recur-sym-replace [d form]
|
||||||
|
"Recursive symbol replacement."
|
||||||
|
(cond
|
||||||
|
[(instance? HySymbol form)
|
||||||
|
(.get d form form)]
|
||||||
|
[(coll? form)
|
||||||
|
((type form) (gfor x form (recur-sym-replace d x)))]
|
||||||
|
[True
|
||||||
|
form]))
|
||||||
|
|
||||||
|
|
||||||
|
(defn rit [form]
|
||||||
|
"Replace `it` with a gensym throughout `form`."
|
||||||
|
(recur-sym-replace {'it (gensym)} form))
|
||||||
|
@ -7,7 +7,13 @@
|
|||||||
|
|
||||||
(defn test-ap-if []
|
(defn test-ap-if []
|
||||||
(ap-if True (assert (is it True)))
|
(ap-if True (assert (is it True)))
|
||||||
(ap-if False True (assert (is it False))))
|
(ap-if False True (assert (is it False)))
|
||||||
|
|
||||||
|
; https://github.com/hylang/hy/issues/1847
|
||||||
|
(setv it "orig")
|
||||||
|
(setv out (ap-if (+ 1 1) (+ it 1) (+ it 10)))
|
||||||
|
(assert (= out 3))
|
||||||
|
(assert (= it "orig")))
|
||||||
|
|
||||||
(defn test-ap-each []
|
(defn test-ap-each []
|
||||||
(setv res [])
|
(setv res [])
|
||||||
|
Loading…
Reference in New Issue
Block a user