From 241d554b0bd5deeb457ff3ce29bfd683cedaabdf Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Tue, 8 Nov 2016 06:28:12 +0200 Subject: [PATCH 1/9] Add lazy sequences into contrib --- docs/contrib/index.rst | 1 + docs/contrib/sequences.rst | 77 ++++++++++++++++++++++ hy/contrib/sequences.hy | 78 +++++++++++++++++++++++ tests/__init__.py | 1 + tests/native_tests/contrib/sequences.hy | 85 +++++++++++++++++++++++++ 5 files changed, 242 insertions(+) create mode 100644 docs/contrib/sequences.rst create mode 100644 hy/contrib/sequences.hy create mode 100644 tests/native_tests/contrib/sequences.hy diff --git a/docs/contrib/index.rst b/docs/contrib/index.rst index ed75add..5ddac2a 100644 --- a/docs/contrib/index.rst +++ b/docs/contrib/index.rst @@ -12,4 +12,5 @@ Contents: flow loop multi + sequences walk diff --git a/docs/contrib/sequences.rst b/docs/contrib/sequences.rst new file mode 100644 index 0000000..318a684 --- /dev/null +++ b/docs/contrib/sequences.rst @@ -0,0 +1,77 @@ +============== +Lazy sequences +============== + +.. versionadded:: 0.12.0 + +Sequences module contains few macros for declaring sequences that are evaluated +only as much as the client code requests elements. Compared to generators they +allow accessing same element multiple times. Since they cache calculated +values, they aren't suited for infinite sequences. However, the implementation +allows recursive definition of sequences, without resulting recursive +computation. + +To use these macros you need to require them and import other types like: + +.. code-block:: hy + + (require [hy.contrib.sequences [defseq seq]]) + (import [hy.contrib.sequences [Sequence end-sequence]]) + +Simplest sequence can be defined as: ``(seq [n] n)``. This defines a sequence +that starts as: ``[0 1 2 3 ...]`` and continues forever. In order to define +a finite sequence, ``end-sequence`` needs to be called to signal end of +the sequence: + +.. code-block:: hy + + (seq [n] + (cond [(< n 5) n] + [true (end-sequence)])) + +This creates following sequence: ``[0 1 2 3 4]``. For such a sequence ``len`` +returns amount of items in sequence and negative indexing is suported. Because +both of thse require evaluating whole sequence, calling such a function would +take forever (or at least until available memory has been exhausted). + +Sequence can be defined recursively. Canonical example of fibonacci numbers +is defined as: + +.. code-block:: hy + + (defseq fibonacci [n] + (cond [(= n 0) 0] + [(= n 1) 1] + [true (+ (get fibonacci (- n 1)) + (get fibonacci (- n 2)))])) + +This results sequence of ``[0 1 1 2 3 5 8 13 21 34 ...]``. + +.. _seq: + +seq +=== + +Usage: ``(seq [n] (* n n)`` + +Creates a sequence defined in terms of ``n``. + +.. _defseq: + +defseq +====== + +Usage: ``(defseq numbers [n] n)`` + +Creates a sequence defined in terms of ``n`` and assigns it to a given name. + +.. _end-sequence: + +end-sequence +============ + +Usage: ``(seq [n] (if (< n 5) n (end-sequence)))`` + +Signals end of a sequence when iterator reaches certain point of sequence. +Internally this is done by raising ``IndexError``, catching that in iterator +and raising ``StopIteration``. diff --git a/hy/contrib/sequences.hy b/hy/contrib/sequences.hy new file mode 100644 index 0000000..20f4c46 --- /dev/null +++ b/hy/contrib/sequences.hy @@ -0,0 +1,78 @@ +;; Copyright (c) 2016 Tuukka Turto +;; +;; 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. +;; + +(defclass Sequence [] + [--init-- (fn [self func] + "initialize a new sequence with a function to compute values" + (setv (. self func) func) + (setv (. self cache) []) + (setv (. self high-water) -1) + nil) + --getitem-- (fn [self n] + "get nth item of sequence" + (if (hasattr n "start") + (if n.step + (genexpr (get self x) [x (range n.start n.stop n.step)]) + (genexpr (get self x) [x (range n.start n.stop 1)])) + (do (when (neg? n) + (len self)) + (if (<= n (. self high-water)) + (get (. self cache) n) + (do (while (< (. self high-water) n) + (setv (. self high-water) (inc (. self high-water))) + (.append (. self cache) (.func self (. self high-water)))) + (get self n)))))) + --iter-- (fn [self] + "create iterator for this sequence" + (setv index 0) + (try (while true + (yield (get self index)) + (setv index (inc index))) + (except [_ IndexError] + (raise StopIteration)))) + --len-- (fn [self] + "length of the sequence, dangerous for infinite sequences" + (setv index (. self high-water)) + (try (while true + (get self index) + (setv index (inc index))) + (except [_ IndexError] + (len (. self cache))))) + --str-- (fn [self] + "string representation of this sequence" + (setv items (list (take 11 self))) + (.format (if (= (len items) 11) + "[{0}, ...]" + "[{0}]") + (.join ", " (map str items)))) + --repr-- (fn [self] + "string representation of this sequence" + (.--str-- self))]) + +(defmacro seq [param seq-code] + `(Sequence (fn ~param ~seq-code))) + +(defmacro defseq [seq-name param seq-code] + `(def ~seq-name (seq ~param ~seq-code))) + +(defn end-sequence [] + "raise IndexError exception to signal end of sequence" + (raise (IndexError "list index out of range"))) diff --git a/tests/__init__.py b/tests/__init__.py index 9580680..9c11bd9 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -21,6 +21,7 @@ from .native_tests.contrib.walk import * # noqa from .native_tests.contrib.multi import * # noqa from .native_tests.contrib.curry import * # noqa from .native_tests.contrib.botsbuildbots import * # noqa +from .native_tests.contrib.sequences import * # noqa if PY3: from .native_tests.py3_only_tests import * # noqa diff --git a/tests/native_tests/contrib/sequences.hy b/tests/native_tests/contrib/sequences.hy new file mode 100644 index 0000000..4d40473 --- /dev/null +++ b/tests/native_tests/contrib/sequences.hy @@ -0,0 +1,85 @@ +;; Copyright (c) 2016 Tuukka Turto +;; +;; 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. +;; + +(require [hy.contrib.sequences [seq defseq]]) + +(import [hy.contrib.sequences [Sequence end-sequence]]) + +(defn test-infinite-sequence [] + "NATIVE: test creating infinite sequence" + (assert (= (list (take 5 (seq [n] n))) + [0 1 2 3 4]))) + +(defn test-indexing-sequence [] + "NATIVE: test indexing sequence" + (defseq shorty [n] + (cond [(< n 10) n] + [true (end-sequence)])) + (assert (= (get shorty 0) + (get (range 10) 0)) + "getting first element failed") + (assert (= (get shorty 5) + (get (range 10) 5)) + "getting 5th element failed") + (assert (= (get shorty -1) + (get (range 10) -1)) + "getting element -1 failed")) + +(defn test-slicing-sequence [] + "NATIVE: test slicing sequence" + (defseq shorty [n] + (cond [(< n 10) n] + [true (end-sequence)])) + (assert (= (first shorty) + (first (range 10))) + "getting first failed") + (assert (= (list (rest shorty)) + (list (rest (range 10)))) + "getting rest failed") + (assert (= (list (cut shorty 2 6)) + (list (cut (range 10) 2 6))) + "cutting 2-6 failed") + (assert (= (list (cut shorty 2 8 2)) + (list (cut (range 10) 2 8 2))) + "cutting 2-8-2 failed") + (assert (= (list (cut shorty 8 2 -2)) + (list (cut (range 10) 8 2 -2))) + "negative cut failed")) + +(defn test-recursive-sequence [] + "NATIVE: test defining a recursive sequence" + (defseq fibonacci [n] + (cond [(= n 0) 0] + [(= n 1) 1] + [true (+ (get fibonacci (- n 1)) + (get fibonacci (- n 2)))])) + (assert (= (first fibonacci) + 0) + "first element of fibonacci didn't match") + (assert (= (second fibonacci) + 1) + "second element of fibonacci didn't match") + (assert (= (get fibonacci 40) + 102334155) + "40th element of fibonacci didn't match") + (assert (= (list (take 9 fibonacci)) + [0 1 1 2 3 5 8 13 21]) + "taking 8 elements of fibonacci didn't match")) From 584a40d9c0f761c1b86be7379ea45ca5c467d613 Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Wed, 9 Nov 2016 05:07:31 +0200 Subject: [PATCH 2/9] Update tests to work with Pytho 2.x In Python 2.x (range 10) is mapped to xrange(10) in Python terms. However, xrange doesn't support slicing, which caused tests to fail. By forxing xrange into list, we have slicing available. --- tests/native_tests/contrib/sequences.hy | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/native_tests/contrib/sequences.hy b/tests/native_tests/contrib/sequences.hy index 4d40473..0b6aeb0 100644 --- a/tests/native_tests/contrib/sequences.hy +++ b/tests/native_tests/contrib/sequences.hy @@ -33,14 +33,15 @@ (defseq shorty [n] (cond [(< n 10) n] [true (end-sequence)])) + (setv 0-to-9 (list (range 10))) (assert (= (get shorty 0) - (get (range 10) 0)) + (get 0-to-9 0)) "getting first element failed") (assert (= (get shorty 5) - (get (range 10) 5)) + (get 0-to-9 5)) "getting 5th element failed") (assert (= (get shorty -1) - (get (range 10) -1)) + (get 0-to-9 -1)) "getting element -1 failed")) (defn test-slicing-sequence [] @@ -48,20 +49,21 @@ (defseq shorty [n] (cond [(< n 10) n] [true (end-sequence)])) + (setv 0-to-9 (list (range 10))) (assert (= (first shorty) - (first (range 10))) + (first 0-to-9)) "getting first failed") (assert (= (list (rest shorty)) - (list (rest (range 10)))) + (list (rest 0-to-9))) "getting rest failed") (assert (= (list (cut shorty 2 6)) - (list (cut (range 10) 2 6))) + (list (cut 0-to-9 2 6))) "cutting 2-6 failed") (assert (= (list (cut shorty 2 8 2)) - (list (cut (range 10) 2 8 2))) + (list (cut 0-to-9 2 8 2))) "cutting 2-8-2 failed") (assert (= (list (cut shorty 8 2 -2)) - (list (cut (range 10) 8 2 -2))) + (list (cut 0-to-9 8 2 -2))) "negative cut failed")) (defn test-recursive-sequence [] From a7f6d1d3f7723aa9c828f0e933d84fa0611af5fb Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Wed, 9 Nov 2016 08:52:18 +0200 Subject: [PATCH 3/9] Add support for multiple statements in sequences --- docs/contrib/sequences.rst | 2 ++ hy/contrib/sequences.hy | 8 ++++---- tests/native_tests/contrib/sequences.hy | 24 ++++++++++++++++++++++++ 3 files changed, 30 insertions(+), 4 deletions(-) diff --git a/docs/contrib/sequences.rst b/docs/contrib/sequences.rst index 318a684..5d9668d 100644 --- a/docs/contrib/sequences.rst +++ b/docs/contrib/sequences.rst @@ -26,6 +26,7 @@ the sequence: .. code-block:: hy (seq [n] + "sequence of 5 integers" (cond [(< n 5) n] [true (end-sequence)])) @@ -40,6 +41,7 @@ is defined as: .. code-block:: hy (defseq fibonacci [n] + "infinite sequence of fibonacci numbers" (cond [(= n 0) 0] [(= n 1) 1] [true (+ (get fibonacci (- n 1)) diff --git a/hy/contrib/sequences.hy b/hy/contrib/sequences.hy index 20f4c46..589b976 100644 --- a/hy/contrib/sequences.hy +++ b/hy/contrib/sequences.hy @@ -67,11 +67,11 @@ "string representation of this sequence" (.--str-- self))]) -(defmacro seq [param seq-code] - `(Sequence (fn ~param ~seq-code))) +(defmacro seq [param &rest seq-code] + `(Sequence (fn ~param (do ~@seq-code)))) -(defmacro defseq [seq-name param seq-code] - `(def ~seq-name (seq ~param ~seq-code))) +(defmacro defseq [seq-name param &rest seq-code] + `(def ~seq-name (seq ~param (do ~@seq-code)))) (defn end-sequence [] "raise IndexError exception to signal end of sequence" diff --git a/tests/native_tests/contrib/sequences.hy b/tests/native_tests/contrib/sequences.hy index 0b6aeb0..9cca5a8 100644 --- a/tests/native_tests/contrib/sequences.hy +++ b/tests/native_tests/contrib/sequences.hy @@ -85,3 +85,27 @@ (assert (= (list (take 9 fibonacci)) [0 1 1 2 3 5 8 13 21]) "taking 8 elements of fibonacci didn't match")) + +(defn test-nested-functions [] + "NATIVE: test that defining nested functions is possible" + (defseq primes [n] + "infinite sequence of prime numbers" + (defn divisible? [n prevs] + "is n divisible by any item in prevs?" + (any (map (fn [x] + (not (% n x))) + prevs))) + (defn previous-primes [n] + "previous prime numbers" + (take (dec n) primes)) + (defn next-possible-prime [n] + "next possible prime after nth prime" + (inc (get primes (dec n)))) + (cond [(= n 0) 2] + [true (do (setv guess (next-possible-prime n)) + (while (divisible? guess (previous-primes n)) + (setv guess (inc guess))) + guess)])) + (assert (= (list (take 10 primes)) + [2 3 5 7 11 13 17 19 23 29]) + "prime sequence didn't match")) From 4219faf532dbf774cef63a9de71d3225df46f920 Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Wed, 30 Nov 2016 23:45:21 +0200 Subject: [PATCH 4/9] Update true, false -> True, False --- hy/contrib/sequences.hy | 7 +++---- tests/native_tests/contrib/sequences.hy | 8 ++++---- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/hy/contrib/sequences.hy b/hy/contrib/sequences.hy index 589b976..8b25df4 100644 --- a/hy/contrib/sequences.hy +++ b/hy/contrib/sequences.hy @@ -24,8 +24,7 @@ "initialize a new sequence with a function to compute values" (setv (. self func) func) (setv (. self cache) []) - (setv (. self high-water) -1) - nil) + (setv (. self high-water) -1)) --getitem-- (fn [self n] "get nth item of sequence" (if (hasattr n "start") @@ -43,7 +42,7 @@ --iter-- (fn [self] "create iterator for this sequence" (setv index 0) - (try (while true + (try (while True (yield (get self index)) (setv index (inc index))) (except [_ IndexError] @@ -51,7 +50,7 @@ --len-- (fn [self] "length of the sequence, dangerous for infinite sequences" (setv index (. self high-water)) - (try (while true + (try (while True (get self index) (setv index (inc index))) (except [_ IndexError] diff --git a/tests/native_tests/contrib/sequences.hy b/tests/native_tests/contrib/sequences.hy index 9cca5a8..6dd65d3 100644 --- a/tests/native_tests/contrib/sequences.hy +++ b/tests/native_tests/contrib/sequences.hy @@ -32,7 +32,7 @@ "NATIVE: test indexing sequence" (defseq shorty [n] (cond [(< n 10) n] - [true (end-sequence)])) + [True (end-sequence)])) (setv 0-to-9 (list (range 10))) (assert (= (get shorty 0) (get 0-to-9 0)) @@ -48,7 +48,7 @@ "NATIVE: test slicing sequence" (defseq shorty [n] (cond [(< n 10) n] - [true (end-sequence)])) + [True (end-sequence)])) (setv 0-to-9 (list (range 10))) (assert (= (first shorty) (first 0-to-9)) @@ -71,7 +71,7 @@ (defseq fibonacci [n] (cond [(= n 0) 0] [(= n 1) 1] - [true (+ (get fibonacci (- n 1)) + [True (+ (get fibonacci (- n 1)) (get fibonacci (- n 2)))])) (assert (= (first fibonacci) 0) @@ -102,7 +102,7 @@ "next possible prime after nth prime" (inc (get primes (dec n)))) (cond [(= n 0) 2] - [true (do (setv guess (next-possible-prime n)) + [True (do (setv guess (next-possible-prime n)) (while (divisible? guess (previous-primes n)) (setv guess (inc guess))) guess)])) From 538d36a7c66cde1a3d5a67dcf447ce288d1c9bb6 Mon Sep 17 00:00:00 2001 From: Tuukka Turto Date: Thu, 1 Dec 2016 00:22:42 +0200 Subject: [PATCH 5/9] Fix grammar --- docs/contrib/sequences.rst | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/docs/contrib/sequences.rst b/docs/contrib/sequences.rst index 5d9668d..e28328d 100644 --- a/docs/contrib/sequences.rst +++ b/docs/contrib/sequences.rst @@ -4,24 +4,24 @@ Lazy sequences .. versionadded:: 0.12.0 -Sequences module contains few macros for declaring sequences that are evaluated -only as much as the client code requests elements. Compared to generators they -allow accessing same element multiple times. Since they cache calculated -values, they aren't suited for infinite sequences. However, the implementation -allows recursive definition of sequences, without resulting recursive -computation. +The Sequences module contains few macros for declaring sequences that are +evaluated only as much as the client code requests elements. Compared to +generators, they allow accessing same the element multiple times. Since they +cache calculated values, they aren't suited for infinite sequences. However, +the implementation allows for recursive definition of sequences, without +resulting recursive computation. -To use these macros you need to require them and import other types like: +To use these macros, you need to require them and import other types like: .. code-block:: hy (require [hy.contrib.sequences [defseq seq]]) (import [hy.contrib.sequences [Sequence end-sequence]]) -Simplest sequence can be defined as: ``(seq [n] n)``. This defines a sequence -that starts as: ``[0 1 2 3 ...]`` and continues forever. In order to define -a finite sequence, ``end-sequence`` needs to be called to signal end of -the sequence: +The simplest sequence can be defined as ``(seq [n] n)``. This defines a +sequence that starts as ``[0 1 2 3 ...]`` and continues forever. In order to +define a finite sequence, ``end-sequence`` needs to be called to signal the end +of the sequence: .. code-block:: hy @@ -30,12 +30,13 @@ the sequence: (cond [(< n 5) n] [true (end-sequence)])) -This creates following sequence: ``[0 1 2 3 4]``. For such a sequence ``len`` -returns amount of items in sequence and negative indexing is suported. Because -both of thse require evaluating whole sequence, calling such a function would -take forever (or at least until available memory has been exhausted). +This creates following sequence: ``[0 1 2 3 4]``. For such a sequence, ``len`` +returns the amount of items in the sequence and negative indexing is supported. +Because both of thse require evaluating the whole sequence, calling such a +function would take forever (or at least until available memory has been +exhausted). -Sequence can be defined recursively. Canonical example of fibonacci numbers +Sequences can be defined recursively. The canonical example of fibonacci numbers is defined as: .. code-block:: hy @@ -47,7 +48,7 @@ is defined as: [true (+ (get fibonacci (- n 1)) (get fibonacci (- n 2)))])) -This results sequence of ``[0 1 1 2 3 5 8 13 21 34 ...]``. +This results the sequence of ``[0 1 1 2 3 5 8 13 21 34 ...]``. .. _seq: From 6bf5ebd8ee81c5c239f089ebc5ccb35a6081a87d Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Wed, 7 Dec 2016 16:04:59 -0800 Subject: [PATCH 6/9] Remove some trailing spaces --- docs/contrib/sequences.rst | 12 ++++++------ hy/contrib/sequences.hy | 4 ++-- tests/native_tests/contrib/sequences.hy | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/contrib/sequences.rst b/docs/contrib/sequences.rst index e28328d..58e7ec0 100644 --- a/docs/contrib/sequences.rst +++ b/docs/contrib/sequences.rst @@ -6,9 +6,9 @@ Lazy sequences The Sequences module contains few macros for declaring sequences that are evaluated only as much as the client code requests elements. Compared to -generators, they allow accessing same the element multiple times. Since they -cache calculated values, they aren't suited for infinite sequences. However, -the implementation allows for recursive definition of sequences, without +generators, they allow accessing same the element multiple times. Since they +cache calculated values, they aren't suited for infinite sequences. However, +the implementation allows for recursive definition of sequences, without resulting recursive computation. To use these macros, you need to require them and import other types like: @@ -20,7 +20,7 @@ To use these macros, you need to require them and import other types like: The simplest sequence can be defined as ``(seq [n] n)``. This defines a sequence that starts as ``[0 1 2 3 ...]`` and continues forever. In order to -define a finite sequence, ``end-sequence`` needs to be called to signal the end +define a finite sequence, ``end-sequence`` needs to be called to signal the end of the sequence: .. code-block:: hy @@ -32,8 +32,8 @@ of the sequence: This creates following sequence: ``[0 1 2 3 4]``. For such a sequence, ``len`` returns the amount of items in the sequence and negative indexing is supported. -Because both of thse require evaluating the whole sequence, calling such a -function would take forever (or at least until available memory has been +Because both of thse require evaluating the whole sequence, calling such a +function would take forever (or at least until available memory has been exhausted). Sequences can be defined recursively. The canonical example of fibonacci numbers diff --git a/hy/contrib/sequences.hy b/hy/contrib/sequences.hy index 8b25df4..1b494d3 100644 --- a/hy/contrib/sequences.hy +++ b/hy/contrib/sequences.hy @@ -50,7 +50,7 @@ --len-- (fn [self] "length of the sequence, dangerous for infinite sequences" (setv index (. self high-water)) - (try (while True + (try (while True (get self index) (setv index (inc index))) (except [_ IndexError] @@ -68,7 +68,7 @@ (defmacro seq [param &rest seq-code] `(Sequence (fn ~param (do ~@seq-code)))) - + (defmacro defseq [seq-name param &rest seq-code] `(def ~seq-name (seq ~param (do ~@seq-code)))) diff --git a/tests/native_tests/contrib/sequences.hy b/tests/native_tests/contrib/sequences.hy index 6dd65d3..50db5a8 100644 --- a/tests/native_tests/contrib/sequences.hy +++ b/tests/native_tests/contrib/sequences.hy @@ -77,7 +77,7 @@ 0) "first element of fibonacci didn't match") (assert (= (second fibonacci) - 1) + 1) "second element of fibonacci didn't match") (assert (= (get fibonacci 40) 102334155) From f4b00aed1712c49b36231882b553af1cdd077147 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Wed, 7 Dec 2016 16:12:57 -0800 Subject: [PATCH 7/9] More copyediting of sequences.rst I removed "they aren't suited for infinite sequences" since it seems like in fact they are, as given in some of the examples and the tests. --- docs/contrib/sequences.rst | 49 +++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/docs/contrib/sequences.rst b/docs/contrib/sequences.rst index 58e7ec0..1c675e0 100644 --- a/docs/contrib/sequences.rst +++ b/docs/contrib/sequences.rst @@ -4,40 +4,40 @@ Lazy sequences .. versionadded:: 0.12.0 -The Sequences module contains few macros for declaring sequences that are -evaluated only as much as the client code requests elements. Compared to -generators, they allow accessing same the element multiple times. Since they -cache calculated values, they aren't suited for infinite sequences. However, -the implementation allows for recursive definition of sequences, without -resulting recursive computation. +The sequences module contains a few macros for declaring sequences that are +evaluated only as much as the client code requires. Unlike generators, they +allow accessing the same element multiple times. They cache calculated values, +and the implementation allows for recursive definition of sequences without +resulting in recursive computation. -To use these macros, you need to require them and import other types like: +To use these macros, you need to require them and import some other names like +so: .. code-block:: hy (require [hy.contrib.sequences [defseq seq]]) (import [hy.contrib.sequences [Sequence end-sequence]]) -The simplest sequence can be defined as ``(seq [n] n)``. This defines a -sequence that starts as ``[0 1 2 3 ...]`` and continues forever. In order to -define a finite sequence, ``end-sequence`` needs to be called to signal the end -of the sequence: +The simplest sequence can be defined as ``(seq [n] n)``. This defines a sequence +that starts as ``[0 1 2 3 ...]`` and continues forever. In order to define a +finite sequence, you need to call ``end-sequence`` to signal the end of the +sequence: .. code-block:: hy (seq [n] "sequence of 5 integers" (cond [(< n 5) n] - [true (end-sequence)])) + [True (end-sequence)])) -This creates following sequence: ``[0 1 2 3 4]``. For such a sequence, ``len`` -returns the amount of items in the sequence and negative indexing is supported. -Because both of thse require evaluating the whole sequence, calling such a -function would take forever (or at least until available memory has been -exhausted). +This creates the following sequence: ``[0 1 2 3 4]``. For such a sequence, +``len`` returns the amount of items in the sequence and negative indexing is +supported. Because both of these require evaluating the whole sequence, calling +one on an infinite sequence would take forever (or at least until available +memory has been exhausted). -Sequences can be defined recursively. The canonical example of fibonacci numbers -is defined as: +Sequences can be defined recursively. For example, the Fibonacci sequence could +be defined as: .. code-block:: hy @@ -45,10 +45,10 @@ is defined as: "infinite sequence of fibonacci numbers" (cond [(= n 0) 0] [(= n 1) 1] - [true (+ (get fibonacci (- n 1)) + [True (+ (get fibonacci (- n 1)) (get fibonacci (- n 2)))])) -This results the sequence of ``[0 1 1 2 3 5 8 13 21 34 ...]``. +This results in the sequence ``[0 1 1 2 3 5 8 13 21 34 ...]``. .. _seq: @@ -75,6 +75,7 @@ end-sequence Usage: ``(seq [n] (if (< n 5) n (end-sequence)))`` -Signals end of a sequence when iterator reaches certain point of sequence. -Internally this is done by raising ``IndexError``, catching that in iterator -and raising ``StopIteration``. +Signals the end of a sequence when an iterator reaches the given +point of the sequence. Internally, this is done by raising +``IndexError``, catching that in the iterator, and raising +``StopIteration``. From e86222c93f4279dcf4770101e0095575584fa833 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Wed, 7 Dec 2016 16:21:17 -0800 Subject: [PATCH 8/9] Allow calling `defseq` without `require`ing `seq` --- hy/contrib/sequences.hy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hy/contrib/sequences.hy b/hy/contrib/sequences.hy index 1b494d3..c2b6bce 100644 --- a/hy/contrib/sequences.hy +++ b/hy/contrib/sequences.hy @@ -70,7 +70,7 @@ `(Sequence (fn ~param (do ~@seq-code)))) (defmacro defseq [seq-name param &rest seq-code] - `(def ~seq-name (seq ~param (do ~@seq-code)))) + `(def ~seq-name (Sequence (fn ~param (do ~@seq-code))))) (defn end-sequence [] "raise IndexError exception to signal end of sequence" From d2342cb69db3b25e054dc526f5bb3283e9416a30 Mon Sep 17 00:00:00 2001 From: Kodi Arfer Date: Wed, 7 Dec 2016 16:32:37 -0800 Subject: [PATCH 9/9] Minor cleanup in sequences.hy --- hy/contrib/sequences.hy | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/hy/contrib/sequences.hy b/hy/contrib/sequences.hy index c2b6bce..f2f4ff3 100644 --- a/hy/contrib/sequences.hy +++ b/hy/contrib/sequences.hy @@ -28,10 +28,11 @@ --getitem-- (fn [self n] "get nth item of sequence" (if (hasattr n "start") - (if n.step - (genexpr (get self x) [x (range n.start n.stop n.step)]) - (genexpr (get self x) [x (range n.start n.stop 1)])) + (genexpr (get self x) [x (range n.start n.stop + (or n.step 1))]) (do (when (neg? n) + ; Call (len) to force the whole + ; sequence to be evaluated. (len self)) (if (<= n (. self high-water)) (get (. self cache) n) @@ -55,10 +56,11 @@ (setv index (inc index))) (except [_ IndexError] (len (. self cache))))) + max-items-in-repr 10 --str-- (fn [self] "string representation of this sequence" - (setv items (list (take 11 self))) - (.format (if (= (len items) 11) + (setv items (list (take (inc self.max-items-in-repr) self))) + (.format (if (> (len items) self.max-items-in-repr) "[{0}, ...]" "[{0}]") (.join ", " (map str items))))