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: `thunk-let'? Date: Sun, 08 Oct 2017 22:12:20 +0200 Message-ID: <87infp9z6j.fsf@web.de> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1507493595 31137 195.159.176.226 (8 Oct 2017 20:13:15 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 8 Oct 2017 20:13:15 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.60 (gnu/linux) Cc: Nicolas Petton , Stefan Monnier To: Emacs Development Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Oct 08 22:13:10 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 1e1Hwh-00073L-WF for ged-emacs-devel@m.gmane.org; Sun, 08 Oct 2017 22:13:08 +0200 Original-Received: from localhost ([::1]:54950 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e1Hwn-000744-MQ for ged-emacs-devel@m.gmane.org; Sun, 08 Oct 2017 16:13:13 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:54759) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1e1HwC-00073z-6Y for emacs-devel@gnu.org; Sun, 08 Oct 2017 16:12:37 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1e1Hw7-0005N6-6w for emacs-devel@gnu.org; Sun, 08 Oct 2017 16:12:36 -0400 Original-Received: from mout.web.de ([212.227.15.14]:56335) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1e1Hw6-0005MY-Si for emacs-devel@gnu.org; Sun, 08 Oct 2017 16:12:31 -0400 Original-Received: from drachen.dragon ([92.74.174.244]) by smtp.web.de (mrweb004 [213.165.67.108]) with ESMTPSA (Nemesis) id 0Lv7eE-1dIhim10ao-010KrE; Sun, 08 Oct 2017 22:12:22 +0200 X-Provags-ID: V03:K0:ctFkB80u0qVHJNPM5iDR60fcg+ZW+ovSMKVK882lIncwyr4pPEK Ed4XqwaRlDgU1zJRAWhaci/g5M8ZPA6NCPCFkfrChEhbWGSBo7UyWM9D58StQuZoELpxU9e BpE5nnlEWx5oTwa6D4f1Y8ZxVnRUyk7YqsmWTX0J5wW8nqqnRVLrckVl5xH8zoq34tsxiFM UNgL/y4S741G4J9W2YOVg== X-UI-Out-Filterresults: notjunk:1;V01:K0:8aR6hz2GuvI=:uRxFfkm4lipaJ1AqUoygI7 XfZmf9IydHPQepjPTv9o4O3dyEpeDcbrDeDM1AGDzvuRiA+SyfBMKrN/lNwYTvISIyW5yeuOK bElgLQ/Ls6x0n1EqV0OZKJ9TrG1zxiZkFl1tj+kpNGncEkr3/vYhZvy+btfetbfTxkcsgCcNQ s+knozlw6LO2ACpYcGP5ZzDIdxm4B7FQZJBf7J6x+PwW6CYuZ7kEk8iI7/KXZEOH1CaKiP/jg rzdUQI72xa2LgbQ2LyDaYq2/QAy7D49+GnxnHvtbj5dZo9H4xJT5nY4f9+AEO+WNdUR7q+IR+ B6rXaL38v0uTgqSFetaEe99YtSZhxswyvKm18aZcQAnbQ2O4NKkC4UUwu0vN1+77udnq3HVtf tSVNiqGl7uppZrr1ccsZbcaadVdZNhSnUcnPZ63GW6VYih94ceNtpKXLIfGPmllgFzPvOyEP1 g3GZWqf/IsqkXjtlpzyz8nUBooJhULwbUvBIHqcIPqQKXktU6+Fi9m22lPFqoXt3kFszAOOMo WwRbBxcgRpGWjzPgAL0Gp9LOHQQBnPbFJ6b/CboaLpynelX9/UcGyDV+LBI5XVcs/9ZXqsVJo NAdm46Wp6GEq0+KBrXonEOKfv8fZqC4RWupohCLDPg/zwgFvVdnupp/hMn2LffxBVhRVWOFOs W4lhCigAlHvTT65Y2d3kcrxR6z7rmcGUaVKfwjtNiXi/jwnaEgjZCldFFF1VflNpbZAmOTkY1 9aHtIIzzTnk7rxDnEj7mOkvRT3jtnc/HPJGA9y7NciQKHsQDZ3a5z7dJlEJbNhTAb7UC3Zp6 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 212.227.15.14 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:219269 Archived-At: Hi, I often want thunks (like in "thunk.el") when I'm not sure if it's necessary to do some calculation (e.g. the result is used in an `if' branch) and want to save the time if not. So I bind a variable not to the expression to eval but to a thunk evaluating it, and use `thunk-force' everywhere I need to refer to the value. It would be cool if the programmer wouldn't need to speak that out, if you could hide away the details and use normal variables instead. You would have a kind of `let' that would look like making bindings to variables just like `let' but the expressions that are assigned are not evaluated before they are needed - maybe never, but also maximally once. I then realized that doing this should be trivial thanks to `cl-symbol-macrolet': instead of binding the original variables, you bind the expressions - wrapped inside `thunk-delay' - to helper vars. Then, you `symbol-macrolet' all original variables to a `thunk-force' of the according helper variable: #+begin_src emacs-lisp ;; -*- lexical-binding: t -*- (eval-when-compile (require 'cl-lib)) (defmacro thunk-let (bindings &rest body) "Like `let' but make delayed bindings. This is like `let' but all binding expressions are not calculated before they are used." (declare (indent 1)) (setq bindings (mapcar (pcase-lambda (`(,var ,binding)) (list (make-symbol (concat (symbol-name var) "_thunk")) var binding)) bindings)) `(let ,(mapcar (pcase-lambda (`(,thunk-var ,_var ,binding)) `(,thunk-var (thunk-delay ,binding))) bindings) (cl-symbol-macrolet ,(mapcar (pcase-lambda (`(,thunk-var ,var ,_binding)) `(,var (thunk-force ,thunk-var))) bindings) ,@body))) (defmacro thunk-let* (bindings &rest body) "Like `let*' but make delayed bindings. This is like `let*' but all binding expressions are not calculated before they are used." (declare (indent 1)) (if (> (length bindings) 1) `(thunk-let (,(car bindings)) (thunk-let ,(cdr bindings) ,@body)) `(thunk-let ,bindings ,@body))) #+end_src An alternative name would be `delayed-let'. I think it would be very convenient. Here is a playground example to test when and if something is calculated (you need lexical-binding mode): #+begin_src emacs-lisp (defmacro calculate-with-message (varname expression) `(progn (message "Calculating %s..." ,varname) (sit-for 2) (prog1 ,expression (message "Calculating %s...done" ,varname) (sit-for 1)))) (thunk-let ((a (calculate-with-message "a" (+ 1 2))) (b (calculate-with-message "b" (* 10 3)))) (1+ b)) ;; etc. #+end_src What do people think about this idea? Thanks, Michael.