From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Michael Heerdegen Newsgroups: gmane.emacs.devel Subject: A generalization of `thunk-let' (was: `thunk-let'?) Date: Fri, 08 Dec 2017 21:38:10 +0100 Message-ID: <87r2s5ez0t.fsf@web.de> References: <87infp9z6j.fsf@web.de> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1512765515 4431 195.159.176.226 (8 Dec 2017 20:38:35 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Fri, 8 Dec 2017 20:38:35 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) Cc: Nicolas Petton , Stefan Monnier To: Emacs Development Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Fri Dec 08 21:38:31 2017 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1eNPPi-00011Y-NO for ged-emacs-devel@m.gmane.org; Fri, 08 Dec 2017 21:38:30 +0100 Original-Received: from localhost ([::1]:38957 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eNPPp-0006vD-VG for ged-emacs-devel@m.gmane.org; Fri, 08 Dec 2017 15:38:38 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:52353) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1eNPPc-0006t5-JL for emacs-devel@gnu.org; Fri, 08 Dec 2017 15:38:25 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1eNPPZ-0006H7-FS for emacs-devel@gnu.org; Fri, 08 Dec 2017 15:38:24 -0500 Original-Received: from mout.web.de ([212.227.15.4]:50106) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1eNPPZ-0006Fp-55 for emacs-devel@gnu.org; Fri, 08 Dec 2017 15:38:21 -0500 Original-Received: from drachen.dragon ([188.106.175.242]) by smtp.web.de (mrweb002 [213.165.67.108]) with ESMTPSA (Nemesis) id 0MSazE-1eXD3H2q6m-00Rc3g; Fri, 08 Dec 2017 21:38:11 +0100 In-Reply-To: <87infp9z6j.fsf@web.de> (Michael Heerdegen's message of "Sun, 08 Oct 2017 22:12:20 +0200") X-Provags-ID: V03:K0:EqyFN+HkxyC2H23ldWxrEvB3F43N/MK81Pt1/6GThBL4os4/vVJ uTCUFKlTpeDuFZSu81ZVztwvh8PuciwpPlSIjzkq7NR9fgPTWK59YOWRCQ3A2QXZDPx+LgW ucbMhZZgo/9BF8sESlyRoeGcINcjY194+yjWKcfbn5yUKV64oUe2QOrRhWEDUMOaoStmqO0 bButi3zaUbJ0XXte+RpAA== X-UI-Out-Filterresults: notjunk:1;V01:K0:+7yNL5XU++M=:n7Nobz1nM+dZOhZa3/Hp7X K7OQVWSOsLg4gS4WHP2LWq8g1ZKymUR2VhvYcp3n/4r+yJptTMeDlxkJfH0LO7/Eomdqp59wH X6gZaky85RzUcQKp9p4o55YxrRLWdIvJVQTrNHMvgOePf01mJq9lgaYpKLdJC4LTXfJxmcwtk 2LA1+TGXmvZLMQDy7TSu/SzWLmUx/xRCR93db9QBmOnfzSjqfPhNct2wcbBNXxOwVtoaFjh0t dlwrBABCLwLYVgBF2mR5B6tljTHc7QlSlqrq1Kq4TIGYz7VvPTAUfuZ3IklEMSTScGH8hM+jF 5US/rD7A+L+1rjQZs1PzFRu2nnvvxmWth61EqiRRQ1bG8DuIFSvplT6TEE4L017CxEbb81TXB 027llJ4KWxGdzPp0AD2pCi15XT5Ef3SQ6WIRqNtSNkbcGUpTWlqcf+aXhuTGY92IjfDARq6B3 vPODwMvTkFNapYXheTnT6MgTdNh0HbKw1omgc+TaypryPKs9csZpbALLNoO92EL2LUIbNnFzn xCAVHVutnBfuVQOCiyS3K1Lg5kxCc3zNPQ1PDylxT9hLRRjF0z5joz2bNdfJaNrc8u1JPdnGC y8Dp9V+C2OzsTWBmpNa58nyZNAX9RXpW+lW9oxUQGgSNPiq/FolqZscepAmUcC9+jvjPS2MsX gjKRb0XoHvN8H18lf52iKidDbbkLlMO6CaXGwPDsG8wbUhW8hvn7AO0j4g49brIm3Yv9pwjlf gAx03cySPflWy9tyAECW5H/8J3J/eMx3ZPL4Tygu+Gc8w32kq/IHikhAU/wy6lp0KxLi6q6T X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.15.4 X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:220799 Archived-At: 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.