[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [SUSPECTED SPAM] Re: `thunk-let'?
From: |
Michael Heerdegen |
Subject: |
Re: [SUSPECTED SPAM] Re: `thunk-let'? |
Date: |
Thu, 09 Nov 2017 16:14:45 +0100 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/27.0.50 (gnu/linux) |
Stefan Monnier <address@hidden> writes:
> I think lazily binding a variable to nil is useless, so I'd drop the
> first pcase branch above.
Makes sense -- done.
> > + :initial-value `(progn ,@body)))
>
> You can use `macroexp-progn` to avoid constructing a `progn` in the
> common case where body is already a single expression.
Done (though the byte compiler already dismissed this redundant `progn'
in every case, so I didn't care about it).
> > +;;;###autoload
> > (defmacro thunk-delay (&rest body)
>
> Maybe a better option is to add a `require` in the expansion of lazy-let?
That should be fine, so I've done it as well.
This is the updated (cumulative) patch:
>From f8bb4d2872c366af45032a3d8d1d2e907c3e4d9d Mon Sep 17 00:00:00 2001
From: Michael Heerdegen <address@hidden>
Date: Thu, 2 Nov 2017 18:45:34 +0100
Subject: [PATCH] Add macros `lazy-let' and `lazy-let*'
* lisp/emacs-lisp/subr-x.el (lazy-let, lazy-let*): New macros.
* test/lisp/emacs-lisp/subr-x-tests.el: Use lexical-binding.
(subr-x-lazy-let-basic-test, subr-x-lazy-let*-basic-test)
(subr-x-lazy-let-bound-vars-cant-be-bound-test)
(subr-x-lazy-let-lazyness-test, subr-x-lazy-let*-lazyness-test)
(subr-x-lazy-let-bad-binding-test): New tests for `lazy-let' and `lazy-let*.
---
etc/NEWS | 3 +++
lisp/emacs-lisp/subr-x.el | 49 +++++++++++++++++++++++++++++++++++
test/lisp/emacs-lisp/subr-x-tests.el | 50 +++++++++++++++++++++++++++++++++++-
3 files changed, 101 insertions(+), 1 deletion(-)
diff --git a/etc/NEWS b/etc/NEWS
index c47ca42d27..451688c665 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -128,6 +128,9 @@ calling 'eldoc-message' directly.
* Lisp Changes in Emacs 27.1
+** The new macros 'lazy-let' and 'lazy-let*' are analogue to `let' and
+`let*' but create bindings that are evaluated lazily.
+
---
** The 'file-system-info' function is now available on all platforms.
instead of just Microsoft platforms. This fixes a 'get-free-disk-space'
diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el
index 8ed29d8659..8e64cbd4ce 100644
--- a/lisp/emacs-lisp/subr-x.el
+++ b/lisp/emacs-lisp/subr-x.el
@@ -245,6 +245,55 @@ string-remove-suffix
(substring string 0 (- (length string) (length suffix)))
string))
+(defmacro lazy-let (bindings &rest body)
+ "Like `let' but create lazy bindings.
+
+BINDINGS is a list of elements of the form (SYMBOL EXPRESSION).
+Any binding EXPRESSION is not evaluated before the variable
+SYMBOL is used for the first time.
+
+It is not allowed to set `lazy-let' or `lazy-let*' bound
+variables."
+ (declare (indent 1) (debug let))
+ (cl-callf2 mapcar
+ (lambda (binding)
+ (pcase binding
+ (`(,(pred symbolp) ,_) binding)
+ (_ (signal 'error (cons "Bad binding in lazy-let"
+ (list binding))))))
+ bindings)
+ (cl-callf2 mapcar
+ (pcase-lambda (`(,var ,binding))
+ (list (make-symbol (concat (symbol-name var) "-thunk"))
+ var binding))
+ bindings)
+ `(progn
+ (require 'thunk)
+ (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 lazy-let* (bindings &rest body)
+ "Like `let*' but create lazy bindings.
+
+BINDINGS is a list of elements of the form (SYMBOL EXPRESSION).
+Any binding EXPRESSION is not evaluated before the variable
+SYMBOL is used for the first time.
+
+It is not allowed to set `lazy-let' or `lazy-let*' bound
+variables."
+ (declare (indent 1) (debug let))
+ (cl-reduce
+ (lambda (expr binding) `(lazy-let (,binding) ,expr))
+ (nreverse bindings)
+ :initial-value (macroexp-progn body)))
+
(provide 'subr-x)
;;; subr-x.el ends here
diff --git a/test/lisp/emacs-lisp/subr-x-tests.el
b/test/lisp/emacs-lisp/subr-x-tests.el
index 0e8871d9a9..c477a63a29 100644
--- a/test/lisp/emacs-lisp/subr-x-tests.el
+++ b/test/lisp/emacs-lisp/subr-x-tests.el
@@ -1,4 +1,4 @@
-;;; subr-x-tests.el --- Testing the extended lisp routines
+;;; subr-x-tests.el --- Testing the extended lisp routines -*-
lexical-binding: t -*-
;; Copyright (C) 2014-2017 Free Software Foundation, Inc.
@@ -538,6 +538,54 @@
(format "abs sum is: %s"))
"abs sum is: 15")))
+
+;; lazy-let tests
+
+(ert-deftest subr-x-lazy-let-basic-test ()
+ "Test whether bindings are established."
+ (should (equal (lazy-let ((x 1) (y 2)) (+ x y)) 3)))
+
+(ert-deftest subr-x-lazy-let*-basic-test ()
+ "Test whether bindings are established."
+ (should (equal (lazy-let* ((x 1) (y (+ 1 x))) (+ x y)) 3)))
+
+(ert-deftest subr-x-lazy-let-bound-vars-cant-be-bound-test ()
+ "Test whether setting or binding a `lazy-let' bound variable fails."
+ (should-error (eval '(lazy-let ((x 1)) (let ((y 7)) (setq x (+ x y)) (* 10
x))) t))
+ (should-error (eval '(lazy-let ((x 1)) (let ((x 2)) x)) t)))
+
+(ert-deftest subr-x-lazy-let-lazyness-test ()
+ "Test for lazyness."
+ (should
+ (equal (let ((x-evalled nil)
+ (y-evalled nil))
+ (lazy-let ((x (progn (setq x-evalled t) (+ 1 2)))
+ (y (progn (setq y-evalled t) (+ 3 4))))
+ (let ((evalled-y y))
+ (list x-evalled y-evalled evalled-y))))
+ (list nil t 7))))
+
+(ert-deftest subr-x-lazy-let*-lazyness-test ()
+ "Test lazyness of `lazy-let*'."
+ (should
+ (equal (let ((x-evalled nil)
+ (y-evalled nil)
+ (z-evalled nil)
+ (a-evalled nil))
+ (lazy-let* ((x (progn (setq x-evalled t) (+ 1 1)))
+ (y (progn (setq y-evalled t) (+ x 1)))
+ (z (progn (setq z-evalled t) (+ y 1)))
+ (a (progn (setq a-evalled t) (+ z 1))))
+ (let ((evalled-z z))
+ (list x-evalled y-evalled z-evalled a-evalled evalled-z))))
+ (list t t t nil 4))))
+
+(ert-deftest subr-x-lazy-let-bad-binding-test ()
+ "Test whether a bad binding causes a compiler error."
+ (should-error (byte-compile (lazy-let ((x 1 1)) x)))
+ (should-error (byte-compile (lazy-let (27) x)))
+ (should-error (byte-compile (lazy-let x x))))
+
(provide 'subr-x-tests)
;;; subr-x-tests.el ends here
--
2.14.2
0001-Add-macros-lazy-let-and-lazy-let.patch
Description: Text Data
Thanks,
Michael.
- Re: [SUSPECTED SPAM] Re: `thunk-let'?, Michael Heerdegen, 2017/11/08
- Re: [SUSPECTED SPAM] Re: `thunk-let'?, Stefan Monnier, 2017/11/08
- Re: [SUSPECTED SPAM] Re: `thunk-let'?,
Michael Heerdegen <=
- Re: `thunk-let'?, Michael Heerdegen, 2017/11/09
- Re: `thunk-let'?, Stefan Monnier, 2017/11/09
- Re: `thunk-let'?, Michael Heerdegen, 2017/11/21
- Re: `thunk-let'?, Eli Zaretskii, 2017/11/21
- Re: `thunk-let'?, Eli Zaretskii, 2017/11/22
- Re: `thunk-let'?, Michael Heerdegen, 2017/11/22
- Re: `thunk-let'?, Eli Zaretskii, 2017/11/22
- Re: `thunk-let'?, Michael Heerdegen, 2017/11/22
- Re: `thunk-let'?, Michael Heerdegen, 2017/11/22
- Re: `thunk-let'?, Pip Cet, 2017/11/23