contrib/anaphoric: More anaphoric macros added
* hy/contrib/anaphoric.hy: The following anaphoric macros have been added `ap-reject` : Opposite of ap-filter, yields the elements when a `pred` evaluates to false `ap-dotimes` : Execute body forms (possibly for side-effects) n times with `it` bound from 0 to n-1 `ap-first` : return the first element that passes predicate `ap-last` : return the last element that passes predicate `ap-reduce`: anaphoric form of reduce that allows `acc` and `it` to create a function that is applied over the list * docs/contrib/anaphoric.rst: updated docs to reflect these changes * tests/__init__.py: updated to explicitly include tests for anaphoric macros
This commit is contained in:
parent
744cd71171
commit
c69c14cc7d
@ -1,6 +1,8 @@
|
||||
====================
|
||||
================
|
||||
Anaphoric Macros
|
||||
====================
|
||||
================
|
||||
|
||||
.. versionadded:: 0.9.12
|
||||
|
||||
The anaphoric macros module makes functional programming in Hy very
|
||||
concise and easy to read.
|
||||
@ -94,3 +96,90 @@ the current element in the iteration.
|
||||
[4, 5]
|
||||
|
||||
|
||||
.. _ap-reject:
|
||||
|
||||
ap-reject
|
||||
=========
|
||||
|
||||
Usage: ``(ap-reject form list)``
|
||||
|
||||
This function does the opposite of ``ap-filter``, it rejects the
|
||||
elements passing the predicate . The special name ``it`` is bound to
|
||||
the current element in the iteration.
|
||||
|
||||
.. code-block:: clojure
|
||||
|
||||
=> (list (ap-reject (> (* it 2) 6) [1 2 3 4 5]))
|
||||
[1, 2, 3]
|
||||
|
||||
|
||||
.. _ap-dotimes:
|
||||
|
||||
ap-dotimes
|
||||
==========
|
||||
|
||||
Usage ``(ap-dotimes n body)``
|
||||
|
||||
This function evaluates the body *n* times, with the special
|
||||
variable ``it`` bound from *0* to *1-n*. It is useful for side-effects.
|
||||
|
||||
.. code-block:: clojure
|
||||
|
||||
=> (setv n [])
|
||||
=> (ap-dotimes 3 (.append n it))
|
||||
=> n
|
||||
[0, 1, 2]
|
||||
|
||||
|
||||
.. _ap-first:
|
||||
|
||||
ap-first
|
||||
========
|
||||
|
||||
Usage ``(ap-first predfn list)``
|
||||
|
||||
This function returns the first element that passes the predicate or
|
||||
``None``, with the special variable ``it`` bound to the current element in
|
||||
iteration.
|
||||
|
||||
.. code-block:: clojure
|
||||
|
||||
=>(ap-first (> it 5) (range 10))
|
||||
6
|
||||
|
||||
|
||||
.. _ap-last:
|
||||
|
||||
ap-last
|
||||
========
|
||||
|
||||
Usage ``(ap-last predfn list)``
|
||||
|
||||
This function returns the last element that passes the predicate or
|
||||
``None``, with the special variable ``it`` bound to the current element in
|
||||
iteration.
|
||||
|
||||
.. code-block:: clojure
|
||||
|
||||
=>(ap-last (> it 5) (range 10))
|
||||
9
|
||||
|
||||
|
||||
.. _ap-reduce:
|
||||
|
||||
ap-reduce
|
||||
=========
|
||||
|
||||
Usage ``(ap-reduce form list &optional initial-value)``
|
||||
|
||||
This function returns the result of applying form to the first 2
|
||||
elements in the body and applying the result and the 3rd element
|
||||
etc. until the list is exhausted. Optionally an initial value can be
|
||||
supplied so the function will be applied to initial value and the
|
||||
first element instead. This exposes the element being iterated as
|
||||
``it`` and the current accumulated value as ``acc``.
|
||||
|
||||
.. code-block:: clojure
|
||||
|
||||
=>(ap-reduce (+ it acc) (range 10))
|
||||
45
|
||||
|
@ -1,6 +1,7 @@
|
||||
;;; Hy anaphoric macros
|
||||
;;
|
||||
;; Copyright (c) 2013 James King <james@agentultra.com>
|
||||
;; 2013 Abhishek L <abhishek.lekshmanan@gmail.com>
|
||||
;;
|
||||
;; Permission is hereby granted, free of charge, to any person obtaining a
|
||||
;; copy of this software and associated documentation files (the "Software"),
|
||||
@ -61,3 +62,42 @@
|
||||
(foreach [val ~lst]
|
||||
(if (pred val)
|
||||
(yield val)))))
|
||||
|
||||
|
||||
(defmacro ap-reject [form lst]
|
||||
"Yield elements returned when the predicate form evaluates to False"
|
||||
`(ap-filter (not ~form) ~lst))
|
||||
|
||||
|
||||
(defmacro ap-dotimes [n &rest body]
|
||||
"Execute body for side effects `n' times, with it bound from 0 to n-1"
|
||||
(unless (numeric? n)
|
||||
(raise (TypeError (.format "{0!r} is not a number" n))))
|
||||
`(ap-each (range ~n) ~@body))
|
||||
|
||||
|
||||
(defmacro ap-first [predfn lst]
|
||||
"Yield the first element that passes `predfn`"
|
||||
`(let [[n (gensym)]]
|
||||
(ap-each ~lst (when ~predfn (setv n it) (break)))
|
||||
n))
|
||||
|
||||
|
||||
(defmacro ap-last [predfn lst]
|
||||
"Yield the last element that passes `predfn`"
|
||||
`(let [[n (gensym)]]
|
||||
(ap-each ~lst (none? n)
|
||||
(when ~predfn
|
||||
(setv n it)))
|
||||
n))
|
||||
|
||||
|
||||
(defmacro ap-reduce [form lst &optional [initial-value None]]
|
||||
"Anaphoric form of reduce, `acc' and `it' can be used for a form"
|
||||
(if (none? initial-value)
|
||||
`(let [[acc (car ~lst)]]
|
||||
(ap-each (cdr ~lst) (setv acc ~form))
|
||||
acc)
|
||||
`(let [[acc ~initial-value]]
|
||||
(ap-each ~lst (setv acc ~form))
|
||||
acc)))
|
||||
|
@ -12,3 +12,4 @@ from .native_tests.when import * # noqa
|
||||
from .native_tests.with_decorator import * # noqa
|
||||
from .native_tests.core import * # noqa
|
||||
from .native_tests.reader_macros import * # noqa
|
||||
from .native_tests.contrib.anaphoric import * # noqa
|
||||
|
0
tests/native_tests/contrib/__init__.hy
Normal file
0
tests/native_tests/contrib/__init__.hy
Normal file
@ -61,3 +61,35 @@
|
||||
[3 4])
|
||||
(assert-equal (list (ap-filter (even? it) [1 2 3 4]))
|
||||
[2 4]))
|
||||
|
||||
(defn test-ap-reject []
|
||||
"NATIVE: testing anaphoric filter"
|
||||
(assert-equal (list (ap-reject (> it 2) [1 2 3 4]))
|
||||
[1 2])
|
||||
(assert-equal (list (ap-reject (even? it) [1 2 3 4]))
|
||||
[1 3]))
|
||||
|
||||
(defn test-ap-dotimes []
|
||||
"NATIVE: testing anaphoric dotimes"
|
||||
(assert-equal (let [[n []]] (ap-dotimes 3 (.append n 3)) n)
|
||||
[3 3 3])
|
||||
(assert-equal (let [[n []]] (ap-dotimes 3 (.append n it)) n)
|
||||
[0 1 2]))
|
||||
|
||||
(defn test-ap-first []
|
||||
"NATIVE: testing anaphoric first"
|
||||
(assert-equal (ap-first (> it 5) (range 10)) 6)
|
||||
(assert-equal (ap-first (even? it) [1 2 3 4]) 2))
|
||||
|
||||
(defn test-ap-last []
|
||||
"NATIVE: testing anaphoric last"
|
||||
(assert-equal (ap-last (> it 5) (range 10)) 9)
|
||||
(assert-equal (ap-last (even? it) [1 2 3 4]) 4))
|
||||
|
||||
(defn test-ap-reduce []
|
||||
"NATIVE: testing anaphoric reduce"
|
||||
(assert-equal (ap-reduce (* acc it) [1 2 3]) 6)
|
||||
(assert-equal (ap-reduce (* acc it) [1 2 3] 6) 36)
|
||||
(assert-equal (ap-reduce (+ acc " on " it) ["Hy" "meth"])
|
||||
"Hy on meth")
|
||||
(assert-equal (ap-reduce (+ acc it) [] 1) 1))
|
||||
|
Loading…
Reference in New Issue
Block a user