aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gtwiwtg.lisp97
1 files changed, 72 insertions, 25 deletions
diff --git a/gtwiwtg.lisp b/gtwiwtg.lisp
index 535c175..87f2bad 100644
--- a/gtwiwtg.lisp
+++ b/gtwiwtg.lisp
@@ -103,12 +103,12 @@ If TIMES is supplied, THUNK will only be called TIMES times."
(map! thunk-proxy (range :to (when times (1- times))))))
(defun from-recurrence (rec n-1 &rest n-m)
- "Creates a generator from a recurrence relation.
+ "Creates a generator from a recurrence relation.
-REC is a function of K arguments.
+REC is a function of K arguments.
-The Nth value of the series generated by the new generator is the result of
-calling REC on the previoius K results.
+The Nth value of the series generated by the new generator is the result of
+calling REC on the previoius K results.
N-1 and N-M are used to initialize the recurrence. (1+ (LENGTH N-M))
should be K, the number of arguments acepted by REC.
@@ -129,7 +129,7 @@ Example
(from-thunk thunk)))
(defun from-input-stream (stream stream-reader)
- "Create a generator from a STREAM.
+ "Create a generator from a STREAM.
You must supply as STREAM-READER function that accepts the stream as
its only argument and returns NIL if the stream has run out of input,
@@ -139,7 +139,30 @@ This function will close the stream when it reaches the end.
A quirk is that the last value returned from this generator is NIL.
-Avoid using with TAKE or PICK-OUT as the file stream will not be closed."
+Avoid using with TAKE or PICK-OUT as the file stream will not be closed.
+
+If you need to use TAKE or PICK-OUT or other consumers that will not
+consume the whole generator, you should evaluate the whole generator
+within an UNWIND-PROTECTing form like WITH-OPEN-FILE.
+
+e.g.
+
+This is fine:
+
+(with-open-file (input \"hey.txt\")
+ (take 2 (from-input-stream
+ input
+ (lambda (s) (read-char s nil nil)))))
+(#\\h #\\e)
+
+But this isn't:
+
+(take 2 (from-input-stream
+ (open \"hey.txt\")
+ (lambda (s) (read-char s nil nil))))
+
+(#\\h #\\e)
+"
(make-instance 'generator!
:state stream
:next-p-fn #'open-stream-p
@@ -156,9 +179,17 @@ Avoid using with TAKE or PICK-OUT as the file stream will not be closed."
"Creates a generator that produces the lines of a file. The stream
to the file is closed when the generator finishes.
-Returns NIL on the last iteration.
+Returns NIL on the last iteration.
+
+Avoid using with TAKE or PICK-OUT as the file stream will not be closed.
+
+If you need to use TAKE or PICK-OUT or other consumers that will not
+consume the whole generator, you should evaluate the whole generator
+within an UNWIND-PROTECTing form such as WITH-OPEN-FILE.
-Avoid using with TAKE or PICK-OUT as the file stream will not be closed."
+See the documentation for FROM-INPUT-STREAM for an example of the
+distinction.
+"
(from-input-stream (open path)
(lambda (stream) (read-line stream nil nil))))
@@ -169,6 +200,14 @@ stream to the file is closed when the generator finishes.
Returns NIL on the last iteration.
Avoid using with TAKE or PICK-OUT as the file stream will not be closed.
+
+If you need to use TAKE or PICK-OUT or other consumers that will not
+consume the whole generator, you should evaluate the whole generator
+within an UNWIND-PROTECTing form such as WITH-OPEN-FILE.
+
+See the documentation for FROM-INPUT-STREAM for an example of the
+distinction.
+
"
(from-input-stream (open path)
(lambda (stream) (read-char stream nil nil))))
@@ -179,7 +218,16 @@ stream to the file is closed when the generator finishes.
Returns NIL on the last iteration.
-Avoid using with TAKE or PICK-OUT as the file stream will not be closed."
+Avoid using with TAKE or PICK-OUT as the file stream will not be closed.
+
+If you need to use TAKE or PICK-OUT or other consumers that will not
+consume the whole generator, you should evaluate the whole generator
+within an UNWIND-PROTECTing form such as WITH-OPEN-FILE.
+
+See the documentation for FROM-INPUT-STREAM for an example of the
+distinction.
+
+"
(from-input-stream (open path :element-type '(unsigned-byte 8))
(lambda (stream) (read-byte stream nil nil))))
@@ -241,7 +289,7 @@ Also, all of the generators must be different from one another. If any
compare EQL then an error is signaled."
(assert (all-good (list* gen gens)))
(dolist (g gens) (make-dirty g)) ;; to ensure gens wont be re-used after use here.
-
+
(let ((orig-fns (mapcar #'next-fn (cons gen gens)))
(orig-preds (mapcar #'next-p-fn (cons gen gens))))
(setf (gen-state gen) (mapcar #'gen-state (cons gen gens))
@@ -302,7 +350,7 @@ THIS FUNCTION MODIFIES AND RETURNS ITS GENERATOR ARGUMENT."
returns a new generator. (INFLATE! FN GEN) returns a generator that is
equivalent to (FUNCALL #'CONCAT! (MAP! FN GEN))
-That is it generates each element of (FN X) for each X in GEN.
+That is it generates each element of (FN X) for each X in GEN.
INFLATE! MODIFIES AND RETURNS ITS GENERATOR ARGUMENT."
(assert (not (dirty-p gen)))
@@ -327,10 +375,10 @@ INFLATE! MODIFIES AND RETURNS ITS GENERATOR ARGUMENT."
(defun concat! (gen &rest gens)
"Returns a generator that is the concatenation of the generators
-passed as arguments.
+passed as arguments.
Each of the arguments to CONCAT! must be different. If any compare
-EQL, an error will be signalled.
+EQL, an error will be signalled.
CONCAT! MODIFIES AND RETURNS ITS FIRST ARGUMENT."
(assert (all-good (list* gen gens)))
@@ -345,12 +393,12 @@ CONCAT! MODIFIES AND RETURNS ITS FIRST ARGUMENT."
;;; CONSUMERS
(defmacro iter ((var-exp gen) &body body)
- "The basic generator consumer.
+ "The basic generator consumer.
VAR-EXP can be either a symbol, or a form sutible for using as the
binding form in DESTRUCTURING-BIND.
-GEN is an expression that should evaluate to a generator.
+GEN is an expression that should evaluate to a generator.
BODY is any form you like, it will be evaluated for each value
procuded by GEN.
@@ -385,12 +433,12 @@ intermediate results are accmulated. INIT-VAL is evaluated to
initialize the value of ACC.
VAR-EXP can be either a symbol, or a form sutible for using as the
-binding form in DESTRUCTURING-BIND.
+binding form in DESTRUCTURING-BIND.
-GEN is an expression that should evaluate to a generator.
+GEN is an expression that should evaluate to a generator.
EXPR is a sigle lisp expression whose value is bound to ACC on each
-iteration.
+iteration.
When iteration has concluded, ACC becomes the value of the FOLD form.
@@ -400,9 +448,9 @@ Example:
55
-Example:
+Example:
-> (fold (acc 0)
+> (fold (acc 0)
((x y) (zip! (times 10) (range :by -1)))
(sqrt (+ acc (* x y))))
@@ -422,10 +470,10 @@ Example:
(defun take (n gen)
"Consumes GEN by collecting its first N values into a list"
(nreverse (fold (xs nil) (x (zip! gen (times (1- n))))
- (cons (car x) xs))))
+ (cons (car x) xs))))
(defun pick-out (indexes gen)
- "Consumes GEN by picking out certain members by their index.
+ "Consumes GEN by picking out certain members by their index.
INDEXES is a list of non-negative integers.
@@ -494,7 +542,7 @@ is minimal among the values of GEN. VALUE is the value of (FUNCALL FN X)"
"A Utility function that inserts ELEM at IDX into BUFFER. For every
other space in BUFFER, the lements of VEC are inserted in order.
-Implicity expects (= (LENGTH BUFFER) (1+ (LENGTH VEC)))
+Implicity expects (= (LENGTH BUFFER) (1+ (LENGTH VEC)))
Not meant for general use. just a utility used by THREAD-THROUGH"
(loop :for i :below (length buffer)
@@ -524,7 +572,7 @@ Not meant for general use. just a utility used by THREAD-THROUGH"
;; primes
-(defun prime-p (n)
+(defun prime-p (n)
(loop
:for x :from 2 :upto (sqrt n)
:when (zerop (mod n x)) :do (return nil)
@@ -532,4 +580,3 @@ Not meant for general use. just a utility used by THREAD-THROUGH"
(defun all-primes ()
(filter! #'prime-p (range :from 1)))
-