aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--gtwiwtg.lisp90
-rw-r--r--package.lisp6
2 files changed, 96 insertions, 0 deletions
diff --git a/gtwiwtg.lisp b/gtwiwtg.lisp
index 35b834c..535c175 100644
--- a/gtwiwtg.lisp
+++ b/gtwiwtg.lisp
@@ -93,6 +93,96 @@ the values passed as ARGS looped forever."
(declare (ignore state))
(values (random arg) nil))))
+
+(defun from-thunk (thunk &optional times)
+ "Creates a generator that produces an inifinte series of values that
+are the return value of (FUNCALL THUNK)
+
+If TIMES is supplied, THUNK will only be called TIMES times."
+ (let ((thunk-proxy (lambda (ignore) (declare (ignore ignore)) (funcall thunk))))
+ (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.
+
+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.
+
+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.
+
+Example
+
+> (let ((fibs (from-recurrence (lambda (n-1 n-2) (+ n-1 n-2)) 0 1)))
+ (take 10 fibs))
+
+(1 1 2 3 5 8 13 21 34 55)
+
+"
+ (let* ((history (cons n-1 n-m))
+ (thunk (lambda ()
+ (let ((nth (apply rec history)))
+ (setf history (cons nth (butlast history)))
+ nth))))
+ (from-thunk thunk)))
+
+(defun from-input-stream (stream stream-reader)
+ "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,
+Non-NIL otherwise.
+
+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."
+ (make-instance 'generator!
+ :state stream
+ :next-p-fn #'open-stream-p
+ :next-fn (lambda (stream)
+ (let ((val (funcall stream-reader stream)))
+ (if val
+ (values val stream)
+ (progn
+ (close stream)
+ (values nil stream)))))))
+
+
+(defun file-lines (path)
+ "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.
+
+Avoid using with TAKE or PICK-OUT as the file stream will not be closed."
+ (from-input-stream (open path)
+ (lambda (stream) (read-line stream nil nil))))
+
+(defun file-chars (path)
+ "Creates a generator that produces the characters of a file. The
+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.
+"
+ (from-input-stream (open path)
+ (lambda (stream) (read-char stream nil nil))))
+
+(defun file-bytes (path)
+ "Creates a generator that produces the bytes of a file. The
+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."
+ (from-input-stream (open path :element-type '(unsigned-byte 8))
+ (lambda (stream) (read-byte stream nil nil))))
+
;;; Some utilities
(defun all-different (things)
diff --git a/package.lisp b/package.lisp
index 40452be..b0f7e21 100644
--- a/package.lisp
+++ b/package.lisp
@@ -7,6 +7,12 @@
#:seq
#:repeater
#:noise
+ #:from-thunk
+ #:from-recurrence
+ #:from-input-stream
+ #:file-lines
+ #:file-chars
+ #:file-bytes
#:yield-to!
#:map!
#:filter!