From: Tomas Hlavaty <tom@logand.com>
To: emacs-devel@gnu.org
Subject: Re: thunk.el: Document that thunk-force == funcall?
Date: Tue, 17 Nov 2020 23:42:39 +0100 [thread overview]
Message-ID: <87lfezwqow.fsf@logand.com> (raw)
In-Reply-To: <87ima33d62.fsf@web.de>
On Tue 17 Nov 2020 at 22:07, Michael Heerdegen <michael_heerdegen@web.de> 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?
next prev parent reply other threads:[~2020-11-17 22:42 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-11-17 15:17 thunk.el: Document that thunk-force == funcall? Michael Heerdegen
2020-11-17 17:08 ` Tomas Hlavaty
2020-11-17 17:38 ` Michael Heerdegen
2020-11-17 18:09 ` Tomas Hlavaty
2020-11-17 21:07 ` Michael Heerdegen
2020-11-17 22:42 ` Tomas Hlavaty [this message]
2020-11-17 23:52 ` Stefan Monnier
2020-11-18 8:01 ` Tomas Hlavaty
2020-11-18 14:04 ` Stefan Monnier
2020-11-18 22:19 ` Tomas Hlavaty
2020-11-18 22:49 ` Stefan Monnier
2020-11-18 23:13 ` Tomas Hlavaty
2020-11-18 23:40 ` Stephen Leake
2020-11-18 9:04 ` Alfred M. Szmidt
2020-11-18 22:21 ` Tomas Hlavaty
2020-11-17 17:32 ` Drew Adams
2020-11-18 23:05 ` Tomas Hlavaty
2020-11-18 23:25 ` Tomas Hlavaty
2020-11-19 11:50 ` Mattias Engdegård
2020-11-19 18:14 ` Tomas Hlavaty
2020-11-19 17:18 ` Tomas Hlavaty
2020-11-19 9:49 ` Nicolas Petton
2020-11-17 21:51 ` Stefan Monnier
2020-11-25 14:16 ` Michael Heerdegen
2020-11-27 17:22 ` Michael Heerdegen
2020-12-17 4:37 ` Michael Heerdegen
2020-12-18 2:58 ` Adam Porter
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=87lfezwqow.fsf@logand.com \
--to=tom@logand.com \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.