aboutsummaryrefslogtreecommitdiffhomepage
path: root/gtwiwtg.lisp
diff options
context:
space:
mode:
authorColin Okay <cbeok@protonmail.com>2020-07-08 11:00:51 -0500
committerColin Okay <cbeok@protonmail.com>2020-07-08 11:00:51 -0500
commitbb2466f19b17f59a6567bf827b5ecb6f4db7fc3d (patch)
treeb97dccf8ff5b6a5a757d6059e0a4e67cffcc58ab /gtwiwtg.lisp
parentdc923f3e1add752f9c1b53390b276100cbad7ed6 (diff)
added more constructors
Diffstat (limited to 'gtwiwtg.lisp')
-rw-r--r--gtwiwtg.lisp90
1 files changed, 90 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)