all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
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?



  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.