[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: thunk.el: Document that thunk-force == funcall?
From: |
Tomas Hlavaty |
Subject: |
Re: thunk.el: Document that thunk-force == funcall? |
Date: |
Tue, 17 Nov 2020 23:42:39 +0100 |
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?
- thunk.el: Document that thunk-force == funcall?, Michael Heerdegen, 2020/11/17
- Re: thunk.el: Document that thunk-force == funcall?, Tomas Hlavaty, 2020/11/17
- Re: thunk.el: Document that thunk-force == funcall?, Michael Heerdegen, 2020/11/17
- Re: thunk.el: Document that thunk-force == funcall?, Tomas Hlavaty, 2020/11/17
- Re: thunk.el: Document that thunk-force == funcall?, Michael Heerdegen, 2020/11/17
- Re: thunk.el: Document that thunk-force == funcall?,
Tomas Hlavaty <=
- Re: thunk.el: Document that thunk-force == funcall?, Stefan Monnier, 2020/11/17
- Re: thunk.el: Document that thunk-force == funcall?, Tomas Hlavaty, 2020/11/18
- Re: thunk.el: Document that thunk-force == funcall?, Stefan Monnier, 2020/11/18
- Re: thunk.el: Document that thunk-force == funcall?, Tomas Hlavaty, 2020/11/18
- Re: thunk.el: Document that thunk-force == funcall?, Stefan Monnier, 2020/11/18
- Re: thunk.el: Document that thunk-force == funcall?, Tomas Hlavaty, 2020/11/18
- Re: thunk.el: Document that thunk-force == funcall?, Stephen Leake, 2020/11/18
Re: thunk.el: Document that thunk-force == funcall?, Alfred M. Szmidt, 2020/11/18
RE: thunk.el: Document that thunk-force == funcall?, Drew Adams, 2020/11/17