From bb2466f19b17f59a6567bf827b5ecb6f4db7fc3d Mon Sep 17 00:00:00 2001 From: Colin Okay Date: Wed, 8 Jul 2020 11:00:51 -0500 Subject: added more constructors --- gtwiwtg.lisp | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 90 insertions(+) (limited to 'gtwiwtg.lisp') 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) -- cgit v1.2.3