From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!not-for-mail From: Michael Heerdegen Newsgroups: gmane.emacs.help Subject: Re: Novice trouble with generator.el Date: Thu, 05 Nov 2015 19:13:28 +0100 Message-ID: <87egg4jovr.fsf@web.de> References: <33a346d6-e0ae-4250-b7b1-9ddb8efab2a8@googlegroups.com> NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: ger.gmane.org 1446748827 9258 80.91.229.3 (5 Nov 2015 18:40:27 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Thu, 5 Nov 2015 18:40:27 +0000 (UTC) To: help-gnu-emacs@gnu.org Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Thu Nov 05 19:40:16 2015 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by plane.gmane.org with esmtp (Exim 4.69) (envelope-from ) id 1ZuPSJ-0008O3-S2 for geh-help-gnu-emacs@m.gmane.org; Thu, 05 Nov 2015 19:40:16 +0100 Original-Received: from localhost ([::1]:34329 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZuPSI-0005tD-Rw for geh-help-gnu-emacs@m.gmane.org; Thu, 05 Nov 2015 13:40:14 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:44818) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZuP2m-0001vP-3N for help-gnu-emacs@gnu.org; Thu, 05 Nov 2015 13:13:53 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1ZuP2j-0004RU-89 for help-gnu-emacs@gnu.org; Thu, 05 Nov 2015 13:13:51 -0500 Original-Received: from plane.gmane.org ([80.91.229.3]:39515) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1ZuP2j-0004Pm-1W for help-gnu-emacs@gnu.org; Thu, 05 Nov 2015 13:13:49 -0500 Original-Received: from list by plane.gmane.org with local (Exim 4.69) (envelope-from ) id 1ZuP2Z-0001R5-Hb for help-gnu-emacs@gnu.org; Thu, 05 Nov 2015 19:13:39 +0100 Original-Received: from ip-90-186-2-82.web.vodafone.de ([90.186.2.82]) by main.gmane.org with esmtp (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Thu, 05 Nov 2015 19:13:39 +0100 Original-Received: from michael_heerdegen by ip-90-186-2-82.web.vodafone.de with local (Gmexim 0.1 (Debian)) id 1AlnuQ-0007hv-00 for ; Thu, 05 Nov 2015 19:13:39 +0100 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 122 Original-X-Complaints-To: usenet@ger.gmane.org X-Gmane-NNTP-Posting-Host: ip-90-186-2-82.web.vodafone.de User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux) Cancel-Lock: sha1:IPcnRmbVh9Foh2Uqgu3jSODUJJY= X-detected-operating-system: by eggs.gnu.org: Genre and OS details not recognized. X-Received-From: 80.91.229.3 X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Original-Sender: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane.org@gnu.org Xref: news.gmane.org gmane.emacs.help:107952 Archived-At: Davin Pearson writes: > The file generator.el in emacs version 25.0.50 looks like a good > implementation of multi-threading, but the documentation is aimed at > experts in using the system. What I would like is a simple example of > how to go about this multi-threading. AFAIR Daniel planned to implement coroutines based on generator.el later. For now, we have the iterators defined there. I agree that the documentation is quite academical. Actually, `iter-defun' is quite easy to use and understand. It is much like a normal defun. If you don't call `iter-yield' or `iter-yield-from' in the body, it is exactly defun. Likewise `iter-lambda'. Let's leave `iter-yield-from' aside for a moment. Write your `iter-defun' like normal code, like a defun that would do all the work at once or return all elements in succession. To return an element and give control back to the caller, just use `iter-yield'. To reinvoke the generator (produce one more element), the caller should use `iter-next' on it. That's all. When the body of the `iter-defun' completes normally (i.e. terminates without calling `iter-yield') the generator has run out of elements and stops/ your coroutine has finished. Here are two real life examples. The first one is an implementation of the sieve of Eratosthenes (don't we use this at home all the time?): --8<---------------cut here---------------start------------->8--- (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)))) --8<---------------cut here---------------end--------------->8--- Both generators never finish, that's why they look like an infloop. Test: (setq g (make-prime-gen)) (iter-next g) ==> 2 (iter-next g) ==> 3 (setq h (make-prime-gen)) (iter-next h) ==> 2 (iter-next g) === 5 Second example: a generator that returns all files in a directory in succession, recursively if you want: --8<---------------cut here---------------start------------->8--- (iter-defun iterator-of-directory-files (directory &optional full match nosort recurse) "Return an iterator of files in DIRECTORY. The arguments FULL, MATCH and NOSORT are like in `directory-files'. Forth optional arg RECURSE non-nil means recurse on subdirectories. If RECURSE is a function, it should accept one argument, a directory file name, and return non-nil when we should recurse into that directory. Any other non-nil value means recurse into every readable subdirectory." (when (file-executable-p directory) ; i.e. DIRECTORY is readable (let ((files (directory-files directory full match nosort)) file) (while (setq file (pop files)) (cond ((not (file-directory-p file)) (iter-yield file)) ((member (file-name-nondirectory (directory-file-name file)) '("." ".."))) (t (iter-yield file) (when (or (and (functionp recurse) (funcall recurse file)) recurse) (iter-yield-from (iterator-of-directory-files file full match nosort recurse))))))))) --8<---------------cut here---------------end--------------->8--- `iter-yield-from' is much like `iter-yield', but instead of returning one element, it takes an iterator as argument and returns the elements it produces, one at a time and one after the other, until that generator runs out, and continues afterwards. The nomenclature of generator vs. iterator is a bit confusing in "generator.el". In that package, a generator is a function that, when called, returns an iterator object. An iterator is a function accepting zero arguments that produces elements. In the above examples, `cross-through-multiples-of', `make-prime-gen' and `iterator-of-directory-files' are generators, `g' and `h' are iterators. HTH, Michael.