emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Gnu Elpa: stream.el: Add some more basic stream operations


From: Michael Heerdegen
Subject: [PATCH] Gnu Elpa: stream.el: Add some more basic stream operations
Date: Thu, 02 Jun 2016 17:42:10 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.94 (gnu/linux)

Hello,

here is a patch that adds some missing stream operations.


---
 packages/stream/stream.el             | 59 +++++++++++++++++++++++++++++++++++
 packages/stream/tests/stream-tests.el | 32 +++++++++++++++++++
 2 files changed, 91 insertions(+)

diff --git a/packages/stream/stream.el b/packages/stream/stream.el
index 22cecac..7728338 100644
--- a/packages/stream/stream.el
+++ b/packages/stream/stream.el
@@ -333,6 +333,65 @@ calling this function."
 (cl-defmethod seq-copy ((stream stream))
   "Return a shallow copy of STREAM."
   (stream-delay stream))
+
+
+;;; More stream operations
+
+(defun stream-scan (function init stream)
+  "Return a stream of successive reduced values for STREAM.
+
+If the elements of a stream s are s_1, s_2, ..., the elements
+S_1, S_2, ... of the stream returned by \(stream-scan f init s\)
+are defined recursively by
+
+  S_1     = init
+  S_(n+1) = (funcall f S_n s_n)
+
+as long as s_n exists.
+
+Example:
+
+   (stream-scan #'* 1 (stream-range 1))
+
+returns a stream of the factorials."
+  (let ((res init))
+    (stream-cons
+     res
+     (seq-map (lambda (el) (setq res (funcall function res el)))
+              stream))))
+
+(defun stream-flush (stream)
+  "Request all elements from STREAM in order for side effects only."
+  (while (not (stream-empty-p stream))
+    (cl-callf stream-rest stream)))
+
+(defun stream-iterate-function (function value)
+  "Return a stream of repeated applications of FUNCTION to VALUE.
+The returned stream starts with VALUE.  Any successive element
+will be found by calling FUNCTION on the preceding element."
+  (stream-cons
+   value
+   (stream-iterate-function function (funcall function value))))
+
+(defun stream-reduce (function init stream)
+  "Reduce two-argument FUNCTION across STREAM starting with INIT."
+  (let ((res init))
+    (stream-flush (seq-map (lambda (el) (setq res (funcall function res el))) 
stream))
+    res))
+
+(defun stream-concatenate (stream-of-streams)
+  "Concatenate all streams in STREAM-OF-STREAMS and return the result.
+All elements in STREAM-OF-STREAMS must be streams.  The result is
+a stream."
+  (stream-reduce #'stream-append (stream-empty) stream-of-streams))
+
+(defun stream-mapconcat (function stream separator)
+  "Apply FUNCTION to each element of STREAM and concat the results as strings.
+In between of each pair of results, stick in SEPARATOR.  This is
+like `mapconcat', but for streams."
+  (if (stream-empty-p stream) ""
+    (let ((mapped (seq-map function stream)))
+      (stream-reduce (lambda (x y) (concat x separator y)) (stream-first 
mapped) (stream-rest mapped)))))
 
 (defun stream-of-directory-files-1 (directory &optional nosort recurse 
follow-links)
   "Helper for `stream-of-directory-files'."
diff --git a/packages/stream/tests/stream-tests.el 
b/packages/stream/tests/stream-tests.el
index 23a54b5..360a405 100644
--- a/packages/stream/tests/stream-tests.el
+++ b/packages/stream/tests/stream-tests.el
@@ -242,5 +242,37 @@
     (should (= 2 (stream-first str)))
     (should (null (stream-pop stream-empty)))))
 
+(ert-deftest stream-scan-test ()
+  (should (eq (seq-elt (stream-scan #'* 1 (stream-range 1)) 4) 24)))
+
+(ert-deftest stream-flush-test ()
+  (should (let* ((times 0)
+                 (count (lambda () (cl-incf times))))
+            (letrec ((make-test-stream (lambda () (stream-cons (progn (funcall 
count) nil)
+                                                          (funcall 
make-test-stream)))))
+              (stream-flush (seq-take (funcall make-test-stream) 5))
+              (eq times 5)))))
+
+(ert-deftest stream-iterate-function-test ()
+  (should (equal (list 0 1 2) (seq-into-sequence (seq-take 
(stream-iterate-function #'1+ 0) 3)))))
+
+(ert-deftest stream-reduce ()
+  (should (eq (stream-reduce #'* 1 (seq-take (stream-range 1) 4)) 24)))
+
+(ert-deftest stream-concatenate-test ()
+  (should (equal (seq-into-sequence
+                  (stream-concatenate
+                   (stream (list (stream (list 1 2 3))
+                                 (stream (list))
+                                 (stream (list 4))
+                                 (stream (list 5 6 7 8 9))))))
+                 (list 1 2 3 4 5 6 7 8 9))))
+
+(ert-deftest stream-mapconcat-test ()
+  (should (equal (stream-mapconcat #'capitalize (stream (list))             
",") ""))
+  (should (equal (stream-mapconcat #'capitalize (stream (list "a"))         
",") "A"))
+  (should (equal (stream-mapconcat #'capitalize (stream (list "a" "b"))     
",") "A,B"))
+  (should (equal (stream-mapconcat #'capitalize (stream (list "a" "b" "c")) 
",") "A,B,C")))
+
 (provide 'stream-tests)
 ;;; stream-tests.el ends here
-- 
2.8.1



Thanks,

Michael.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]