From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Tomas Hlavaty Newsgroups: gmane.emacs.devel Subject: Re: thunk.el: Document that thunk-force == funcall? Date: Tue, 17 Nov 2020 23:42:39 +0100 Message-ID: <87lfezwqow.fsf@logand.com> References: <871rgs3tdx.fsf@web.de> <874klnnc6t.fsf@logand.com> <87o8jv3mue.fsf@web.de> <87y2izlusu.fsf@logand.com> <87ima33d62.fsf@web.de> Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="33311"; mail-complaints-to="usenet@ciao.gmane.io" To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Tue Nov 17 23:43:49 2020 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1kf9hV-0008Zr-Q7 for ged-emacs-devel@m.gmane-mx.org; Tue, 17 Nov 2020 23:43:49 +0100 Original-Received: from localhost ([::1]:57904 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kf9hU-000159-Sa for ged-emacs-devel@m.gmane-mx.org; Tue, 17 Nov 2020 17:43:48 -0500 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:56764) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kf9gc-0000dM-Um for emacs-devel@gnu.org; Tue, 17 Nov 2020 17:42:57 -0500 Original-Received: from logand.com ([37.48.87.44]:46660) by eggs.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kf9gT-0007XB-TM for emacs-devel@gnu.org; Tue, 17 Nov 2020 17:42:49 -0500 Original-Received: by logand.com (Postfix, from userid 1001) id E4A971A2B40; Tue, 17 Nov 2020 23:42:43 +0100 (CET) X-Mailer: emacs 26.3 (via feedmail 11-beta-1 I) In-Reply-To: <87ima33d62.fsf@web.de> Received-SPF: pass client-ip=37.48.87.44; envelope-from=tom@logand.com; helo=logand.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/11/17 17:42:44 X-ACL-Warn: Detected OS = Linux 2.2.x-3.x [generic] X-Spam_score_int: -18 X-Spam_score: -1.9 X-Spam_bar: - X-Spam_report: (-1.9 / 5.0 requ) BAYES_00=-1.9, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:259320 Archived-At: On Tue 17 Nov 2020 at 22:07, Michael Heerdegen wrote: > The result might not be defined at think time. It might depend on "the > environment". > > Say the code loops over a list of files or so (not known at think time). > The thunk could "contain" a test that might take long (e.g. something > that might need to look at the file's contents) but the result is > interesting only sometimes, depending on the result of other tests (also > not known at think time). do you have a specific example i could learn from? i use thunks a lot for a kind of minimalist portable streams (sometimes called generators in lisp), e.g. see https://logand.com/sw/emacs-pdf/file/emacs-pdf.el.html#l198 i am hoping to learn new use-case or trick here your use-case seems to be like this: (dolist (f (directory-files "/tmp/" t)) (when (and (some-other-test-p) (something-is-the-case-but-it-takes-long-to-find-out-p)) (do-something))) why does something-is-the-case-but-it-takes-long-to-find-out-p need to be a thunk? the special form `and' is already lazy and skips computing something-is-the-case-but-it-takes-long-to-find-out-p when some-other-test-p is false. also it is usually better to not depend on implicit environment but to use function arguments when possible. in this case something-is-the-case-but-it-takes-long-to-find-out-p should take the f as arg (it might need to look at the file's contents after all): (dolist (f (directory-files "/tmp/" t)) (when (and (some-other-test-p f) (something-is-the-case-but-it-takes-long-to-find-out-p f)) (do-something f))) one use-case for thunks here would be to make dolist lazy: (setq lexical-binding t) (require 'cl) (defun brook (x) (etypecase x (list (lambda () (pop x))))) (defun brook-count (brook) (loop with z = nil while (setq z (funcall brook)) count z)) (defun filter-brook (fn brook) (lambda () (block yield (let (z) (while (setq z (funcall brook)) (when (funcall fn z) (return-from yield z))))))) ;; now we can for example count regular files as we pull them lazily (let ((some-other-test-p 'file-regular-p)) (brook-count (filter-brook some-other-test-p (brook (directory-files "/tmp/" t))))) (defun map-brook (fn brook) (lambda () (let ((x (funcall brook))) (when x (funcall fn x))))) (defun brook-collect (brook) (loop with z = nil while (setq z (funcall brook)) collect z)) (defun sha256sum (file) (with-temp-buffer (call-process "sha256sum" file (current-buffer)) (buffer-substring-no-properties (point-min) (+ 64 (point-min))))) ;; now we can for example collect sha256sum of each regular file (let ((some-other-test-p 'file-regular-p) (something-is-the-case-but-it-takes-long-to-find-out-p 'sha256sum)) (brook-collect (map-brook something-is-the-case-but-it-takes-long-to-find-out-p (filter-brook some-other-test-p (brook (directory-files "/tmp/" t)))))) ;; or display progress during slow computation (defun progress-brook (brook) (lambda () (let ((z (funcall brook))) (when z (message (format "progress-brook: %s" z)) z)))) (let ((some-other-test-p 'file-regular-p) (something-is-the-case-but-it-takes-long-to-find-out-p 'sha256sum)) (brook-collect (progress-brook (map-brook something-is-the-case-but-it-takes-long-to-find-out-p (progress-brook (filter-brook some-other-test-p (brook (directory-files "/tmp/" t)))))))) i can imagine that we might for example want to show progress also during computation of sha256sum. something-is-the-case-but-it-takes-long-to-find-out-p would then return thunk and be run "step by step" like this: (defun flat-brook (&rest brooks) (lambda () (block yield (while brooks (let ((z (funcall (car brooks)))) (cond ((functionp z) (push z brooks)) (z (return-from yield z)) (t (pop brooks)))))))) (let ((some-other-test-p 'file-regular-p) (something-is-the-case-but-it-takes-long-to-find-out-p (lambda (f) ;; i cannot easily show progress during sha256sum here so ;; lets immitate that by showing progress before and after (let ((pending (list (lambda () (message "before sha256sum %s" f)) (lambda () (let ((z (sha256sum f))) (message "sha256sum %s %s" f z) z)) (lambda () (message "after sha256sum %s" f))))) (lambda () (when pending (funcall (pop pending)))))))) (brook-collect (flat-brook (map-brook something-is-the-case-but-it-takes-long-to-find-out-p (filter-brook some-other-test-p (brook (directory-files "/tmp/" t))))))) but in which use-case should something-is-the-case-but-it-takes-long-to-find-out-p be a thunk?