[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Generator Examples
From: |
Michael Heerdegen |
Subject: |
Re: Generator Examples |
Date: |
Sun, 25 Sep 2016 02:16:45 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/25.1.50 (gnu/linux) |
Hey raman,
> I'm attaching a short texinfo file containing a couple of examples of
> using generators in Emacs Lisp.
Great. This would be an improvement for the manual indeed.
> The texinfo manual contains one example which I found confusing in
> parts:
Yeah, the current doc is more for people already familiar with the
concept.
> 1. The example has a nested call to iter-yield -- not sure why
Just to demonstrate how it behaves, I think. It's probably not very
common/useful in practise.
> 2. I still dont quite understand the purpose of the optional argument
> to iter-next, an example that leverages it would be good to have.
I think it's more useful if you think of generators as coroutines. A
simple real life example would be: you have implemented a counter as a
generator (generating 1, 2, ...), and when you restart it, you want to
add a certain increment to its count so far before continuing.
> @lisp
> (iter-defun fibonacci-iter ()
> "Return a Fibonacci sequence generator."
> (let ((a 1)
> (b 1))
> (while t
> (iter-yield a)
> (cl-psetq a b b (+ a b )))))
> @end lisp
Looks good (but could we get rid of the a bit uncommon `cl-psetq'). I
remember that the suggested convention was to call the iter-defun a
generator, and the return value an iterator (in this regard, the
docstring would be wrong).
FWIW, some time ago a had posted a similar example, implementing a
generator of the prime numbers:
(iter-defun cross-through-multiples-of (n)
"Repeat indefinitely: Return `t' N-1 times, then return `nil' once."
(let ((i (1- n)))
(while t
(if (zerop i) (progn (setq i (1- n)) (iter-yield nil))
(iter-yield t)
(cl-decf i)))))
(iter-defun make-prime-gen ()
"Return a generator of the prime numbers."
(let ((n 2) (sieve '()))
(while t
(when (cl-every #'identity (mapcar #'iter-next sieve))
;; a new prime!
(push (cross-through-multiples-of n) sieve)
(iter-yield n))
(cl-incf n))))
> A generator that takes a list and returns an iterator over that list:
>
> @lisp
> (iter-defun list-iter (l)
> "Return an iterator that iterates over list `l'."
> (let ((local(copy-sequence l)))
> (while local (iter-yield (pop local)))))
> @end lisp
Isn't the `copy-sequence' redundant (popping the local variable doesn't
alter the original list)?
> @lisp
> ;;; Create a list iterator:
>
> (setq l-iter (list-iter '(a b c d e)))
> ;;; Loop through the iterator, collecting values:
> (cl-loop for e iter-by l-iter collect e)
> @end lisp
>
> @bye
To improve the doc even further, I think it would be good if we could as
well:
- Underline the difference between generators and its "instances"
(iterators), and that multiple iterators of the same "type" have
independent inner states.
- Have an example that doesn't create lists at the end, to underline
that it is a different concept, and/or
- Have a real life example (something like tree traversal, e.g. a
generator of directory files or so) that is an improvement compared to
using list.
Regards,
Michael.