aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--examples.lisp31
-rw-r--r--gtwiwtg.lisp84
-rw-r--r--package.lisp4
3 files changed, 118 insertions, 1 deletions
diff --git a/examples.lisp b/examples.lisp
index 221c78e..df50a23 100644
--- a/examples.lisp
+++ b/examples.lisp
@@ -118,4 +118,33 @@ vector VEC, one at a time."
(zip! (range) (file-lines file))))
-;; find all export expressions in my bashrc file
+
+;;; 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))))))
+ (concatenate 'string
+ (apply #'nconc
+ (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 35f830d..00534f5 100644
--- a/gtwiwtg.lisp
+++ b/gtwiwtg.lisp
@@ -640,6 +640,90 @@ Caveat:
(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
+generators run out of values.
+
+Examples:
+
+> (intersperse! (seq '(:name :job :hobbies))
+ (seq '(\"buckaroo banzai\"
+ \"rocker\"
+ (\"neuroscience\"
+ \"particle physics\"
+ \"flying fighter jets\"))))
+
+> (collect *)
+
+ (:NAME \"buckaroo banzai\" :JOB \"rocker\" :HOBBIES
+ (\"neuroscience\" \"particle physics\" \"flying fighter jets\"))
+
+> (intersperse! (times 5) (repeater 'a 'b 'c) (range :by -10))
+
+> (collect *)
+
+ (0 A 0 1 B -10 2 C -20 3 A -30 4 B -40)
+ "
+ (inflate! #'seq (apply #'zip! gen1 gen2 gens)))
+
+(defun truncate! (n gen)
+ "Shrinks a generator to generate a series of at most N values."
+ (map! #'first (zip! gen (times n))))
+
+(defun inject! (fn gen)
+ "Injects an effect into a generator. Use this to add a side-effect
+to the value generation process. The new generator produces exactly
+the same values as GEN.
+
+Possibly good for debugging.
+
+Example:
+
+> (map! #'reverse
+ (inject! #'print ; look at values before they're reversed
+ (zip! (range)
+ (repeater :cool :beans)
+ (seq \"banzai!\"))))
+
+> (collect *)
+
+ (0 :COOL #\b) ;these are printed to stdout
+ (1 :BEANS #\a)
+ (2 :COOL #\n)
+ (3 :BEANS #\z)
+ (4 :COOL #\a)
+ (5 :BEANS #\i)
+
+ ((#\b :COOL 0) ; and this is what collect returns
+ (#\a :BEANS 1)
+ (#\n :COOL 2)
+ (#\z :BEANS 3)
+ (#\a :COOL 4)
+ (#\i :BEANS 5))
+
+"
+ (map! (lambda (x) (funcall fn x) x) gen))
+
+(defun disperse! (n gen)
+ "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
(defmacro for (var-exp gen &body body)
diff --git a/package.lisp b/package.lisp
index 1923e2e..9916cf3 100644
--- a/package.lisp
+++ b/package.lisp
@@ -26,6 +26,10 @@
#:skip-while!
#:nfurcate!
#:partition!
+ #:intersperse!
+ #:truncate!
+ #:inject!
+ #:disperse!
#:for
#:fold
#:collect