diff options
-rw-r--r-- | examples.lisp | 31 | ||||
-rw-r--r-- | gtwiwtg.lisp | 84 | ||||
-rw-r--r-- | package.lisp | 4 |
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 |