diff --git a/docs/contrib/anaphoirc.rst b/docs/contrib/anaphoirc.rst new file mode 100644 index 0000000..0a487c2 --- /dev/null +++ b/docs/contrib/anaphoirc.rst @@ -0,0 +1,96 @@ +==================== +Anaphoric Macros +==================== + +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 (http://en.wikipedia.org/wiki/Anaphoric_macro) + +Macros +====== + +.. _ap-each: + +ap-each +------- + +Usage: ``(ap-each [1 2 3 4 5] (print it))`` + +Evaluate the form for each element in the list for side-effects. + + +.. _ap-each-while: + +ap-each-while +============= + +Usage: ``(ap-each-while list pred body)`` + +Evaluate the form for each element where the predicate form returns +True. + +.. code-block:: clojure + + => (ap-each-while [1 2 3 4 5 6] (< it 4) (print it)) + 1 + 2 + 3 + +.. _ap-map: + +ap-map +====== + +Usage: ``(ap-map form list)`` + +The anaphoric form of map works just like regular map except that +instead of a function object it takes a Hy form. The special name, +``it`` is bound to the current object from the list in the iteration. + +.. code-block:: clojure + + => (list (ap-map (* it 2) [1 2 3])) + [2, 4, 6] + + +.. _ap-map-when: + +ap-map-when +=========== + +Usage: ``(ap-map-when predfn rep list)`` + +Evaluate a mapping over the list using a predicate function to +determin when to apply the form. + +.. code-block:: clojure + + => (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: + +ap-filter +========= + +Usage: ``(ap-filter form list)`` + +As with ``ap-map`` we take a special form instead of a function to +filter the elements of the list. The special name ``it`` is bound to +the current element in the iteration. + +.. code-block:: clojure + + => (list (ap-filter (> (* it 2) 6) [1 2 3 4 5])) + [4, 5] + + diff --git a/docs/contrib/index.rst b/docs/contrib/index.rst new file mode 100644 index 0000000..80b7697 --- /dev/null +++ b/docs/contrib/index.rst @@ -0,0 +1,10 @@ + +Contrib Modules Index +===================== + +Contents: + +.. toctree:: + :maxdepth: 3 + + anaphoric diff --git a/docs/index.rst b/docs/index.rst index 299c59e..102929a 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -49,3 +49,4 @@ Contents: tutorial hacking language/index + contrib/index diff --git a/hy/contrib/anaphoric.hy b/hy/contrib/anaphoric.hy new file mode 100644 index 0000000..d0a163a --- /dev/null +++ b/hy/contrib/anaphoric.hy @@ -0,0 +1,63 @@ +;;; Hy anaphoric macros +;; +;; Copyright (c) 2013 James King +;; +;; Permission is hereby granted, free of charge, to any person obtaining a +;; copy of this software and associated documentation files (the "Software"), +;; to deal in the Software without restriction, including without limitation +;; the rights to use, copy, modify, merge, publish, distribute, sublicense, +;; and/or sell copies of the Software, and to permit persons to whom the +;; Software is furnished to do so, subject to the following conditions: +;; +;; The above copyright notice and this permission notice shall be included in +;; all copies or substantial portions of the Software. +;; +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +;; DEALINGS IN THE SOFTWARE. +;; +;;; These macros make writing functional programs more concise + + +(defmacro ap-each [lst &rest body] + "Evaluate the body form for each element in the list." + `(foreach [it ~lst] ~@body)) + + +(defmacro ap-each-while [lst form &rest body] + "Evalutate the body form for each element in the list while the + predicate form evaluates to True." + `(let [[p (lambda [it] ~form)]] + (foreach [it ~lst] + (if (p it) + ~@body + (break))))) + + +(defmacro ap-map [form lst] + "Yield elements evaluated in the form for each element in the list." + `(let [[f (lambda [it] ~form)]] + (foreach [v ~lst] + (yield (f v))))) + + +(defmacro ap-map-when [predfn rep lst] + "Yield elements evaluated for each element in the list when the + predicate function returns True." + `(let [[f (lambda [it] ~rep)]] + (foreach [it ~lst] + (if (~predfn it) + (yield (f it)) + (yield it))))) + + +(defmacro ap-filter [form lst] + "Yield elements returned when the predicate form evaluates to True." + `(let [[pred (lambda [it] ~form)]] + (foreach [val ~lst] + (if (pred val) + (yield val))))) diff --git a/tests/native_tests/contrib/anaphoric.hy b/tests/native_tests/contrib/anaphoric.hy new file mode 100644 index 0000000..7fb08f4 --- /dev/null +++ b/tests/native_tests/contrib/anaphoric.hy @@ -0,0 +1,63 @@ +;; Copyright (c) 2013 James King + +;; Permission is hereby granted, free of charge, to any person obtaining a +;; copy of this software and associated documentation files (the "Software"), +;; to deal in the Software without restriction, including without limitation +;; the rights to use, copy, modify, merge, publish, distribute, sublicense, +;; and/or sell copies of the Software, and to permit persons to whom the +;; Software is furnished to do so, subject to the following conditions: + +;; The above copyright notice and this permission notice shall be included in +;; all copies or substantial portions of the Software. + +;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +;; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +;; FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +;; DEALINGS IN THE SOFTWARE. + +;;;; some simple helpers + +(require hy.contrib.anaphoric) + +(defn assert-true [x] + (assert (= True x))) + +(defn assert-false [x] + (assert (= False x))) + +(defn assert-equal [x y] + (assert (= x y))) + +(defn test-ap-each [] + "NATIVE: testing anaphoric each" + (setv res []) + (ap-each [1 2 3 4] (.append res it)) + (assert-equal res [1 2 3 4])) + +(defn test-ap-each-while [] + "NATIVE: testing anaphoric each-while" + (setv res []) + (ap-each-while [2 2 4 3 4 5 6] (even? it) (.append res it)) + (assert-equal res [2 2 4])) + +(defn test-ap-map [] + "NATIVE: testing anaphoric map" + (assert-equal (list (ap-map (* it 3) [1 2 3])) + [3 6 9]) + (assert-equal (list (ap-map (* it 3) [])) + [])) + +(defn test-ap-map-when [] + "NATIVE: testing anaphoric map-when" + (assert-equal (list (ap-map-when even? (* it 2) [1 2 3 4])) + [1 4 3 8])) + +(defn test-ap-filter [] + "NATIVE: testing anaphoric filter" + (assert-equal (list (ap-filter (> it 2) [1 2 3 4])) + [3 4]) + (assert-equal (list (ap-filter (even? it) [1 2 3 4])) + [2 4]))