unofficial mirror of emacs-devel@gnu.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

  List information: https://www.gnu.org/software/emacs/

* 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 public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).