diff options
author | Colin Okay <cbeok@protonmail.com> | 2020-08-04 18:46:41 -0500 |
---|---|---|
committer | Colin Okay <cbeok@protonmail.com> | 2020-08-04 18:46:41 -0500 |
commit | 08710ae637fcb28d5f1552a1e37c93857c6ca841 (patch) | |
tree | 7421858901de5ffb8ba8aacb94c9d41ec0d48040 | |
parent | 83dcb72f6fa2527f48a1e64f15e1866bf674e7e4 (diff) |
removed experimental combinators
-rw-r--r-- | README.md | 45 | ||||
-rw-r--r-- | examples.lisp | 28 | ||||
-rw-r--r-- | gtwiwtg.lisp | 145 |
3 files changed, 3 insertions, 215 deletions
@@ -87,34 +87,6 @@ example apears at the end of the document, following the tutorial. ``` -### A Silly Scrambler - -``` lisp - -;; see examples.lisp for defuns of PAD and CHUNK - -> (defun scramble (n str) - (assert (< n (length str))) - (let ((str (pad str (* n (ceiling (/ (length str) n)))))) - (apply #'concatenate 'string - (mapcar #'collect (disperse! n (seq str)))))) - -> (defun descramble (n str) - (concatenate 'string - (collect - (apply #'intersperse! - (mapcar #'seq (chunk n str)))))) - - -> (scramble 3 "this will be scrambled, ya dig?") - -"tsi rbdyd?h lbsal,ai iwlecme g " - -> (descramble 3 *) -"this will be scrambled, ya dig? " - -``` - ## Tutorial GTWIWTG is a tiny library for creating and using generators. @@ -289,23 +261,6 @@ Here are some simple examples of their use: intermingles the values of its argument generators, in the order they appear in the argument list. -And some experimental tools: - -- `(nfurcate! n gen)` returns a list of `n` new generators, each - producing the same elements as of `gen`. -- `(partition! pred gen)` returns a list of two new generators, the - first generating the memebers of `gen` that pass the predicate - `pred`, and the second generating those that don't. -- `(disperse! n gen)` is sort of the opposite of - `intersperse!`. Returns a list of `n` generators, the first produces - every nth value from `gen`, the second produces every nth+1 values - from `gen`, and so on. - -The above are marked as EXPERIMENTAL because they may not be -in line with the the spirit of this library. I wanted the library to -produce constant-memory operations. However, when you consume the -generators that the above forms produce, then new memory will be -consed during consumption. See the docstrings for both forms for more details. ### A Word Of Warning! diff --git a/examples.lisp b/examples.lisp index 0a40a0c..8760b8a 100644 --- a/examples.lisp +++ b/examples.lisp @@ -119,31 +119,3 @@ vector VEC, one at a time." -;;; Silly Scrambler ;;; - - -(defun pad (str len &optional (pad-char #\Space)) - (let ((i 0)) - (with-output-to-string (out) - (loop :for c :across str :do (incf i) (princ c out)) - (loop :while (< i len) :do (incf i) (princ pad-char out))))) - -(defun scramble (n str) - (assert (< n (length str))) - (let ((str (pad str (* n (ceiling (/ (length str) n)))))) - (apply #'concatenate 'string - (mapcar #'collect (disperse! n (seq str)))))) - - -(defun chunk (n str) - (assert (zerop (mod (length str) n))) - (let ((size (/ (length str) n))) - (loop - :for i :below (length str) :by size - :collect (subseq str i (+ i size)) ))) - -(defun descramble (n str) - (concatenate 'string - (collect - (apply #'intersperse! - (mapcar #'seq (chunk n str)))))) diff --git a/gtwiwtg.lisp b/gtwiwtg.lisp index f1a5038..cb299bd 100644 --- a/gtwiwtg.lisp +++ b/gtwiwtg.lisp @@ -474,12 +474,12 @@ Error Conditions: - If any of the generators compare EQL, an error will be signalled. - If any of the generators has been used elsewhere, an error will be sigalled. " - (sully-when-clean (list* gen gens)) - (inflate! #'identity (seq (list* gen gens)) + (sully-when-clean (cons gen gens)) + (inflate! #'identity (seq (cons gen gens)) ;; in the case that not all arguments are consumed, ;; explicitly stop each one at clean-up time. :extra-cleanup (lambda () - (dolist (g (list* gen gens)) (stop g))))) + (dolist (g (cons gen gens)) (stop g))))) (defun zip! (gen &rest gens) "Is a shortcut for (MAP! #'LIST GEN1 GEN2 ...)" @@ -536,126 +536,6 @@ Error Conditions: (dolist (g all-gens) (stop g)))))) -(defun skip! (n gen) - "EXPERIMENTAL. Might be removed. - -Returns the generator GEN but without the first N elements. - -Caveats: - - - It is possible that SKIP! will skip the whole source generator, - returning an empty gernator. -" - (sully-when-clean (list gen)) - (dotimes (x n) (when (has-next-p gen) (next gen))) - (setf (dirty-p gen ) nil) - gen) - -(defun skip-while! (pred gen) - "EXPERIMENTAL. Might be removed. - -Returns the generator GEN but without the first N elements for -which PRED is non-nil. - -Caveat: - - It is possible that, for finite generators, skip-while! will skip - the whole generated sequence. - - If the generator is infinite, then skip-while! MIGHT never return. -" - (sully-when-clean (list gen)) - (let ((cached (list nil))) - (loop - :while (has-next-p gen) - :for val = (next gen) - :unless (funcall pred val) - :do - (setf (car cached) val) - (return)) - (setf (dirty-p gen) nil) - (concat! (seq cached) gen))) - - -(defun nfurcate! (count source-generator) - "EXERIMENTAL. MAY BE REMOVED - -Return a list of COUNT copies of GEN. - -Caveat: - - - The generators produced by NFURCATE! allocate new memory as they - are consumed. This allocation can be O(COUNT * SIZE) in space - complexity, where SIZE is the size of GEN. Hence, use with caution - on infinite generators. - - - The SOURCE-GENERATOR will be cleaned up only after all of the - returned generators have been consumed. That is if you make some - generators using NFURCATE! but do use them, then the - SOURCE-GENERATOR may never be cleaned up. I.e. if it is backed by a - stream, that stream will not be closed. - -" - (sully-when-clean (list source-generator)) - (let ((qs (loop :for _ :below count :collect (make-queue))) - (stop-cells (loop :for _ :below count :collect (list nil)))) - (loop - :for build-q :in qs - :for stop-cell :in stop-cells - :collect - (let ((local-q build-q) - (local-stop stop-cell)) - - (from-thunk-until - (lambda () - (cond ((not (queue-empty-p local-q)) - (dequeue local-q)) - - ((has-next-p source-generator) - (let ((next-v (next source-generator))) - (loop :for q :in qs :do (enqueue next-v q)) - (dequeue local-q))) - - (t (error "Attempted to get next from a spent generator.")))) - - :until - (lambda () - (and (not (has-next-p source-generator)) - (queue-empty-p local-q))) - - :clean-up - (lambda () - (setf (car local-stop) t) - (when (every #'car stop-cells) - (stop source-generator)))))))) - -(defun partition! (pred gen) - "EXPERIMENTAL. MAY BE REMOVED. - -Return a list of two generators that looks like (PASSING FAILING) - -PASSING is a generator that produces the values of GEN that pass the -predicate PRED - -FAILING is a generator that produces the values of GEN that do not -pass the predicate PRED - -Caveat: - - - The generators produced by PARTITION! allocate new memory as you - consume them. This allocation may be O(2 * SIZE) in space - complexity, where SIZE is the size of GEN. Hence, use with caution - on infinite generators. - -- The generator GEN will be cleaned up only after both returned - generators have been. Hence, you must consume both or you risk - leaving some clean up undone. E.g. If GEN is a stream backed - generator, the stream will not be closed until both PASSING and - FAILING have been consumed. - -" - (destructuring-bind (gen1 gen2) (nfurcate! 2 gen) - (list (filter! pred gen1) - (filter! (complement pred) gen2)))) - (defun intersperse! (gen1 gen2 &rest gens) "Produces a generator that intersperses one value from each of its argument generators, one after the other, until any of those @@ -725,25 +605,6 @@ Example: " (map! (lambda (x) (funcall fn x) x) gen)) -(defun disperse! (n gen) - "EXPERIMENTAL. MAY BE REMOVED. - -Produces a list of N gnerators, G1,...,GN. - -G1 produces every Nth value of GEN, including first value. -G2 produces every Nth+1 value of GEN, including the second value. -... -GN produces every Nth + (N-1) value of GEN, including the (N-1)th value. - -This is sort of the opposite of INTERSPERSE!." - (loop - :for i :below n - :for cloned :in (nfurcate! n gen) - :collect - (let ((j i)) - (map! #'second - (filter! (lambda (pair) (= j (mod (first pair) n))) - (indexed! cloned)))))) ;;; CONSUMERS |