Clean up the implementations of anaphoric macros

This commit is contained in:
Kodi Arfer 2019-12-21 11:38:26 -05:00
parent b12c930444
commit bafd919605
2 changed files with 32 additions and 40 deletions

View File

@ -19,74 +19,54 @@
(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."
(setv p (gensym)) `(for [it ~lst]
`(do (unless ~form
(defn ~p [it] ~form) (break))
(for [it ~lst] ~@body))
(if (~p it)
~@body
(break)))))
(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."
(setv v (gensym 'v) f (gensym 'f)) `(gfor it ~lst ~form))
`((fn []
(defn ~f [it] ~form)
(for [~v ~lst]
(yield (~f ~v))))))
(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."
(setv f (gensym)) `(gfor it ~lst (if (~predfn it) ~rep it)))
`((fn []
(defn ~f [it] ~rep)
(for [it ~lst]
(if (~predfn it)
(yield (~f it))
(yield 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."
(setv pred (gensym)) `(gfor it ~lst :if ~form it))
`((fn []
(defn ~pred [it] ~form)
(for [val ~lst]
(if (~pred val)
(yield val))))))
(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"
`(ap-filter (not ~form) ~lst)) `(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"
`(ap-each (range ~n) ~@body)) `(for [it (range ~n)]
~@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`"
(with-gensyms [n] `(next
`(do (gfor it ~lst :if ~predfn it)
(setv ~n None) None))
(ap-each ~lst (when ~predfn (setv ~n it) (break)))
~n)))
(defmacro ap-last [predfn lst] (defmacro ap-last [predfn lst]
"Yield the last element that passes `predfn`" "Yield the last element that passes `predfn`"
(with-gensyms [n] (setv x (gensym))
`(do `(do
(setv ~n None) (setv ~x None)
(ap-each ~lst (none? ~n) (for [it ~lst :if ~predfn]
(when ~predfn (setv ~x it))
(setv ~n it))) ~x))
~n)))
(defmacro! ap-reduce [form o!lst &optional [initial-value None]] (defmacro! ap-reduce [form o!lst &optional [initial-value None]]
@ -97,7 +77,8 @@
(setv ~g!lst (iter ~g!lst)) (setv ~g!lst (iter ~g!lst))
(next ~g!lst)) (next ~g!lst))
initial-value)) initial-value))
(ap-each ~g!lst (setv acc ~form)) (for [it ~g!lst]
(setv acc ~form))
acc)) acc))

View File

@ -0,0 +1,11 @@
;; Copyright 2019 the authors.
;; This file is part of Hy, which is free software licensed under the Expat
;; license. See the LICENSE.
(require [hy.extra.anaphoric [ap-last]])
(defn test-anaphoric-single-require []
; https://github.com/hylang/hy/issues/1853#issuecomment-568192529
; `ap-last` should work even if `require`d without anything else
; from the anaphoric module.
(assert (= (ap-last (> it 0) [-1 1 0 3 2 0 -1]) 2)))