all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Michael Heerdegen <michael_heerdegen@web.de>
To: Emacs Development <emacs-devel@gnu.org>
Cc: Nicolas Petton <nicolas@petton.fr>,
	Stefan Monnier <monnier@iro.umontreal.ca>
Subject: A generalization of `thunk-let' (was: `thunk-let'?)
Date: Fri, 08 Dec 2017 21:38:10 +0100	[thread overview]
Message-ID: <87r2s5ez0t.fsf@web.de> (raw)
In-Reply-To: <87infp9z6j.fsf@web.de> (Michael Heerdegen's message of "Sun, 08 Oct 2017 22:12:20 +0200")

Hello,

I had an idea for something that turned out to generalize `thunk-let' -
I called it `dep-let' ("dep" like "dependency") for now.  I wonder if
it's a useful or a silly idea.

Say, you write a user interface, and it includes some toggle commands.
When one of these toggle commands is called, the code will probably need
to recompute some variables to adopt their bindings to the new set of
options.  So the code needs to introduce some functions to recompute the
variables, and the developer must keep an eye on where these functions
need to be called - it's something that makes code changes a bit
painful.

The idea is to make such dependencies explicit, but hide the
recomputation stuff at the same time.  Bindings are lazy, and are
recomputed lazily when one of the dependencies changes.

Here is a proof-of-concept implementation:

#+begin_src emacs-lisp
;; -*- lexical-binding: t -*-

(require 'cl-lib)

(defun with-short-term-memory (function)
  "Wrap FUNCTION to cache the last arguments/result pair."
  (let ((cached nil))
    (lambda (&rest args)
      (pcase cached
        (`(,(pred (equal args)) . ,result) result)
        (_ (cdr (setq cached (cons args (apply function args)))))))))

(defmacro dep-let (bindings &rest body)
  "Make dependent bindings and evaluate BODY.

This is similar to `let', but BINDINGS is a list of elements
(VAR DEPS EXPRESSION).  DEPS is a list of symbols declaring that the
computation of this binding depends on the values of these symbols.

All bindings are lazy.  Whenever VAR is referenced and one of the DEPS has
changed its value (modulo #'equal), the binding is silently
recomputed."
  (declare (indent 1))
  (cl-callf2 mapcar
      (pcase-lambda (`(,var ,deps ,binding))
        (list (make-symbol (concat (symbol-name var) "-helper"))
              var deps binding))
      bindings)
  `(let ,(mapcar
          (pcase-lambda (`(,helper-var ,_var ,deps ,binding))
            `(,helper-var (with-short-term-memory (lambda ,deps ,binding))))
          bindings)
     (cl-symbol-macrolet
         ,(mapcar (pcase-lambda (`(,helper-var ,var ,deps ,_binding))
                    `(,var (funcall ,helper-var ,@deps)))
                  bindings)
       ,@body)))
#+end_src

You get `thunk-let' when you specify empty dependency lists.

It may be useful to generalize the `equal' test, or to allow to specify
something else as dependency (e.g. the result of a (fast) function
call).

Here are some very simple

#+begin_src emacs-lisp
;;; Examples:

(let ((a 1)
      (b 2))
  (dep-let ((sum-of-a-and-b (a b) (progn (message "Calculating %d + %d" a b) (+ a b))))
    (list sum-of-a-and-b
          (1+ sum-of-a-and-b)
          (* 2 sum-of-a-and-b)
          (progn (setq a 5)
                 sum-of-a-and-b))))

|- Calculating 1 + 2
|- Calculating 5 + 2
=> (3 4 6 7)


;; Dependencies can be recursive:

(let ((a 1)
      (b 2)
      (c 3))
  (dep-let ((a+b   (a b)   (+ a b))
            (a+b+c (a+b c) (+ a+b c)))
    (list a+b
          a+b+c
          (progn (setq a 10) a+b+c))))

==> (3 6 15)
#+end_src


Thanks,

Michael.



  parent reply	other threads:[~2017-12-08 20:38 UTC|newest]

Thread overview: 77+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-10-08 20:12 `thunk-let'? Michael Heerdegen
2017-10-08 22:25 ` `thunk-let'? Michael Heerdegen
2017-10-09  3:10 ` `thunk-let'? Stefan Monnier
2017-10-09 11:40   ` `thunk-let'? Michael Heerdegen
2017-10-09 14:07     ` `thunk-let'? Michael Heerdegen
2017-10-09 14:27       ` `thunk-let'? Michael Heerdegen
2017-10-09 15:38     ` [SUSPECTED SPAM] `thunk-let'? Stefan Monnier
2017-11-08 17:22       ` Michael Heerdegen
2017-11-08 18:02         ` Stefan Monnier
2017-11-09 15:14           ` Michael Heerdegen
2017-11-09 18:39             ` `thunk-let'? Michael Heerdegen
2017-11-09 18:48               ` `thunk-let'? Stefan Monnier
2017-11-22  2:50                 ` `thunk-let'? Michael Heerdegen
2017-11-22  3:43                   ` `thunk-let'? Eli Zaretskii
2017-11-22 16:16                     ` `thunk-let'? Eli Zaretskii
2017-11-22 19:25                       ` `thunk-let'? Michael Heerdegen
2017-11-22 20:00                         ` `thunk-let'? Eli Zaretskii
2017-11-23  2:59                       ` `thunk-let'? Michael Heerdegen
2017-11-23  4:15                         ` `thunk-let'? Michael Heerdegen
2017-11-23 16:34                           ` `thunk-let'? Pip Cet
2017-11-23 23:41                             ` `thunk-let'? Michael Heerdegen
2017-11-24  8:37                               ` `thunk-let'? Eli Zaretskii
2017-11-24  8:51                                 ` `thunk-let'? Stefan Monnier
2017-11-24  9:16                                   ` `thunk-let'? Eli Zaretskii
2017-11-24 13:33                                     ` `thunk-let'? Stefan Monnier
2017-11-27  5:21                                 ` `thunk-let'? Michael Heerdegen
2017-11-27 13:34                                   ` `thunk-let'? Stefan Monnier
2017-11-27 15:44                                     ` `thunk-let'? Eli Zaretskii
2017-11-30 15:19                                       ` `thunk-let'? Michael Heerdegen
2017-11-24  8:36                           ` `thunk-let'? Eli Zaretskii
2017-11-30 15:17                             ` `thunk-let'? Michael Heerdegen
2017-11-30 16:06                               ` `thunk-let'? Eli Zaretskii
2017-12-01  8:02                                 ` `thunk-let'? Michael Heerdegen
2017-11-23 16:04                         ` `thunk-let'? Eli Zaretskii
2017-11-22 17:44                   ` `thunk-let'? Gemini Lasswell
2017-11-22 18:04                     ` `thunk-let'? Noam Postavsky
2017-11-22 18:31                       ` `thunk-let'? Michael Heerdegen
2017-11-22 18:29                     ` `thunk-let'? Michael Heerdegen
2017-11-22 19:54                     ` `thunk-let'? Stefan Monnier
2017-11-22 22:47                       ` `thunk-let'? Michael Heerdegen
2017-11-10 10:01             ` [SUSPECTED SPAM] `thunk-let'? Eli Zaretskii
2017-11-08 18:04         ` Eli Zaretskii
2017-11-08 22:22           ` `thunk-let'? Michael Heerdegen
2017-11-08 23:06             ` `thunk-let'? Drew Adams
2017-11-09 17:20             ` `thunk-let'? Eli Zaretskii
2017-11-09 17:39               ` `thunk-let'? Clément Pit-Claudel
2017-11-09 18:06                 ` `thunk-let'? Michael Heerdegen
2017-11-09 21:05                   ` `thunk-let'? Drew Adams
2017-11-09 23:07                     ` Sandbox subr-x? (was: `thunk-let'?) Michael Heerdegen
2017-11-09 23:54                       ` Drew Adams
2017-11-10  7:57                       ` Eli Zaretskii
2017-11-09 21:48                   ` `thunk-let'? Clément Pit-Claudel
2017-11-09 22:43                     ` `thunk-let'? Michael Heerdegen
2017-11-10  7:48                     ` `thunk-let'? Eli Zaretskii
2017-11-09 18:14               ` `thunk-let'? Michael Heerdegen
2017-11-09 20:26                 ` `thunk-let'? Eli Zaretskii
2017-11-09 23:13                   ` `thunk-let'? Michael Heerdegen
2017-11-10  7:58                     ` `thunk-let'? Eli Zaretskii
2017-11-11 15:20                       ` `thunk-let'? Michael Heerdegen
2017-11-11 15:40                         ` `thunk-let'? Eli Zaretskii
2017-11-10 10:10               ` `thunk-let'? Nicolas Petton
2017-11-09 14:34           ` [SUSPECTED SPAM] `thunk-let'? Michael Heerdegen
2017-11-09 17:12             ` Eli Zaretskii
2017-11-09 15:19           ` Michael Heerdegen
2017-10-09  8:00 ` `thunk-let'? Nicolas Petton
2017-12-08 20:38 ` Michael Heerdegen [this message]
2017-12-08 21:16   ` A generalization of `thunk-let' Stefan Monnier
2017-12-09 10:33     ` Michael Heerdegen
2017-12-10  4:47       ` Stefan Monnier
2017-12-10  5:34         ` John Wiegley
2017-12-12 14:41         ` Michael Heerdegen
2017-12-13 13:52           ` Michael Heerdegen
2017-12-13 14:09             ` Stefan Monnier
2017-12-13 14:37               ` Michael Heerdegen
2018-01-12 20:03     ` Michael Heerdegen
2017-12-09 21:59   ` A generalization of `thunk-let' (was: `thunk-let'?) Richard Stallman
2017-12-10 17:03     ` A generalization of `thunk-let' Michael Heerdegen

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=87r2s5ez0t.fsf@web.de \
    --to=michael_heerdegen@web.de \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@iro.umontreal.ca \
    --cc=nicolas@petton.fr \
    /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.