From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Mark Oteiza Newsgroups: gmane.emacs.bugs Subject: bug#28254: 26.0.50; SRFI-2 and-let* Date: Sun, 3 Sep 2017 18:39:59 -0400 Message-ID: <20170903223959.GA15782@holos.localdomain> References: <87a82kdb4e.fsf@holos> <87inh36sap.fsf@users.sourceforge.net> <20170902021043.GA7509@holos.localdomain> <878thx7qcc.fsf@users.sourceforge.net> <20170902041424.GA21189@holos.localdomain> <87tw0lzn7w.fsf@drachen> <20170902133604.GA27251@holos.localdomain> <87vakzwu5e.fsf@drachen> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii; format=flowed X-Trace: blaine.gmane.org 1504478495 10608 195.159.176.226 (3 Sep 2017 22:41:35 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 3 Sep 2017 22:41:35 +0000 (UTC) User-Agent: Mutt/1.9.0 (2017-09-02) Cc: 28254@debbugs.gnu.org, Noam Postavsky To: Michael Heerdegen Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Mon Sep 04 00:41:20 2017 Return-path: Envelope-to: geb-bug-gnu-emacs@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 1dodZu-00020Z-JL for geb-bug-gnu-emacs@m.gmane.org; Mon, 04 Sep 2017 00:41:18 +0200 Original-Received: from localhost ([::1]:33239 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dodZz-00030n-U0 for geb-bug-gnu-emacs@m.gmane.org; Sun, 03 Sep 2017 18:41:23 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:34089) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1dodZk-0002zq-Ar for bug-gnu-emacs@gnu.org; Sun, 03 Sep 2017 18:41:13 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1dodZf-0004nq-8s for bug-gnu-emacs@gnu.org; Sun, 03 Sep 2017 18:41:08 -0400 Original-Received: from debbugs.gnu.org ([208.118.235.43]:38368) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1dodZf-0004nj-2t for bug-gnu-emacs@gnu.org; Sun, 03 Sep 2017 18:41:03 -0400 Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1dodZe-0001G6-DK for bug-gnu-emacs@gnu.org; Sun, 03 Sep 2017 18:41:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: Mark Oteiza Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Sun, 03 Sep 2017 22:41:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 28254 X-GNU-PR-Package: emacs X-GNU-PR-Keywords: Original-Received: via spool by 28254-submit@debbugs.gnu.org id=B28254.15044784094776 (code B ref 28254); Sun, 03 Sep 2017 22:41:02 +0000 Original-Received: (at 28254) by debbugs.gnu.org; 3 Sep 2017 22:40:09 +0000 Original-Received: from localhost ([127.0.0.1]:47049 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dodYn-0001Ex-5y for submit@debbugs.gnu.org; Sun, 03 Sep 2017 18:40:09 -0400 Original-Received: from mail-qk0-f175.google.com ([209.85.220.175]:37175) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1dodYl-0001El-9C for 28254@debbugs.gnu.org; Sun, 03 Sep 2017 18:40:07 -0400 Original-Received: by mail-qk0-f175.google.com with SMTP id k126so16708209qkb.4 for <28254@debbugs.gnu.org>; Sun, 03 Sep 2017 15:40:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=udel-edu.20150623.gappssmtp.com; s=20150623; h=date:from:to:cc:subject:message-id:references:mime-version :content-disposition:in-reply-to:user-agent; bh=WO+r3IAr1E9rZPTgg++oYnC6pIt9LFLhHgBHm1YScwM=; b=ZuLZZYaakl6WRzZvYh6oSL3K+zh12yGGphToXjald62IdPOGJAs5BaKdTw0t37Qcyv YrVYVdruiumadg+pwn5adhtsx4b9gGEzIJoYeAywYYDc5fr5PhRh2JQGBDDsrlVHhIgV Uol9ZykD6a6koewFQOLyHRIV1tvPSGar/pRG2Yn8LW9plgI2uBrvPfuI6dr5D3yMi4GF uxt83USpVc9us+IxKtr3bTiBMWjkxY/kQqVv2KTaTgU5te/U/s5W8AgI9FLKlVV/R9y5 8NjnUGZ329pM6TvG1PR+XDTXJd/9W7Fd7VXwfM2+jlbc/xcT9ANi3ZdATkbX2yfv/7gK i0Jg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:date:from:to:cc:subject:message-id:references :mime-version:content-disposition:in-reply-to:user-agent; bh=WO+r3IAr1E9rZPTgg++oYnC6pIt9LFLhHgBHm1YScwM=; b=GruYGOTrA+90eP8rKP1Hf7B83/MqdlywYknVWHqmLasyLuYJkpTd0IYV5Vt5BtLbvU s8OdJn50CRSxsNkOVQ59NL8dsQ2JZ4W3/4eMp2a8vmzQwZ8ArpT0q3Et/tYFT5EyqOda l5hNVC5uLxOBr6KIYtrXyDuPOU5PovK93fWV50OK59bOS9cUYju58NC4PHA41im4+yCN Axstpg7ZAxE7t+FLH+6gx+9nmotc/GSWP/8BmG1pW+W2W1w+POlFFGMfdpjCUT2yURWw OX2PqWbQ6nvGzNLjHR/W0mPTIRboBTRdPZJvd3LkxhrEYEutEkPX4kYa89QFQfgEblxl I9KQ== X-Gm-Message-State: AHPjjUh1cPHmW0zf1x3oyJknD43Yq+X1ce6rroioTSPnItX+0W/jhB5u 81qbIFfF9yc+BCBB8M1wbA== X-Google-Smtp-Source: ADKCNb72lLp5ydN7pF8wPf+cyAOj2/UQUpk4MVlFCZXtAkBy/i/8g+HhovzgXZBV+Grfd+JAcmMWvw== X-Received: by 10.55.93.67 with SMTP id r64mr11044641qkb.358.1504478401324; Sun, 03 Sep 2017 15:40:01 -0700 (PDT) Original-Received: from holos.localdomain (pool-173-64-88-95.bltmmd.fios.verizon.net. [173.64.88.95]) by smtp.gmail.com with ESMTPSA id j61sm3973143qte.30.2017.09.03.15.40.00 (version=TLS1_2 cipher=ECDHE-RSA-CHACHA20-POLY1305 bits=256/256); Sun, 03 Sep 2017 15:40:00 -0700 (PDT) Original-Received: by holos.localdomain (Postfix, from userid 1000) id AA6C866207; Sun, 3 Sep 2017 18:39:59 -0400 (EDT) Content-Disposition: inline In-Reply-To: <87vakzwu5e.fsf@drachen> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 208.118.235.43 X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane.org@gnu.org Original-Sender: "bug-gnu-emacs" Xref: news.gmane.org gmane.emacs.bugs:136558 Archived-At: On 03/09/17 at 07:48pm, Michael Heerdegen wrote: >Noam Postavsky writes: > >> I think I'd be okay with dropping support for the S = (S nil) thing in >> foo-let macros, so that all of the above would give (void-variable x). >> Although perhaps the incompatibility with plain let would be annoying? >> To be honest I hardly ever make use of S = (S nil) in plain let either >> so it wouldn't hit me at all. > >I think the main use case is to declare a local variable when you don't >care about the init value. In the case of if-let, S = (S nil) is not >useful, since you can't use that binding neither in the "then" clause >(because it won't be executed) nor in the "else" clauses (which ignore >all bindings). > >Even if an `if-let' form is the result of a macro expansion, the S = (S >nil) case isn't of any value. So I see no reasons to not drop support >for it. If I'm understanding correctly, it is being agreed that (let ((x 1)) (and-let* (x) x)) ;; => 1 because the macro expands to (let* ((x (and t x))) (if x x)) The following patch achieves this, though it breaks some existing subr-x tests which I haven't yet looked at carefully. diff --git a/lisp/emacs-lisp/subr-x.el b/lisp/emacs-lisp/subr-x.el index 849ac19d6a..ec1990110a 100644 --- a/lisp/emacs-lisp/subr-x.el +++ b/lisp/emacs-lisp/subr-x.el @@ -83,10 +83,22 @@ thread-last `(internal--thread-argument nil ,@forms)) (defsubst internal--listify (elt) - "Wrap ELT in a list if it is not one." - (if (not (listp elt)) - (list elt) - elt)) + "Wrap ELT in a list if it is not one. +If ELT is of the form ((EXPR)), listify (EXPR) with a dummy symbol." + (message "%S" elt) + (cond + ;; could this be cleaner? + ((null elt) (list elt)) + ((symbolp elt) (list elt elt)) + ((nlistp elt) (list elt)) + ((and (null (cdr elt)) + (atom (car elt))) + (list (cl-gensym) (car elt))) + ((and (null (cdr elt)) + (let ((form (car elt))) + (or (listp form) (atom form)))) + (list (cl-gensym) (car elt))) + (t elt))) (defsubst internal--check-binding (binding) "Check BINDING is properly formed." @@ -98,7 +110,10 @@ internal--check-binding (defsubst internal--build-binding-value-form (binding prev-var) "Build the conditional value form for BINDING using PREV-VAR." - `(,(car binding) (and ,prev-var ,(cadr binding)))) + (let ((var (car binding))) + (if (and (null (cdr binding)) (atom (car binding)) (not (symbolp (car binding)))) + `(,var (and ,prev-var ,var)) + `(,var (and ,prev-var ,(cadr binding)))))) (defun internal--build-binding (binding prev-var) "Check and build a single BINDING with PREV-VAR." @@ -122,8 +137,11 @@ if-let* Each binding is evaluated in turn with `let*', and evaluation stops if a binding value is nil. If all are non-nil, the value of THEN is returned, or the last form in ELSE is returned. + Each element of VARLIST is a symbol (which is bound to nil) or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the value of VALUEFORM). +An element can additionally be of the form (EXPR), which is +evaluated and checked for nil. In the special case you only want to bind a single value, VARLIST can just be a plain tuple. \n(fn VARLIST THEN ELSE...)" @@ -134,27 +152,43 @@ if-let* (not (listp (car bindings)))) ;; Adjust the single binding case (setq bindings (list bindings))) - `(let* ,(internal--build-bindings bindings) - (if ,(car (internal--listify (car (last bindings)))) - ,then - ,@else))) + (if bindings + `(let* ,(setq bindings (internal--build-bindings bindings)) + (if ,(caar (last bindings)) + ,then + ,@else)) + `(let* () ,then))) (defmacro when-let* (bindings &rest body) "Bind variables according to VARLIST and conditionally eval BODY. Each binding is evaluated in turn with `let*', and evaluation stops if a binding value is nil. If all are non-nil, the value of the last form in BODY is returned. + Each element of VARLIST is a symbol (which is bound to nil) or a list (SYMBOL VALUEFORM) (which binds SYMBOL to the value of VALUEFORM). +An element can additionally be of the form (EXPR), which is +evaluated and checked for nil. In the special case you only want to bind a single value, VARLIST can just be a plain tuple. \n(fn VARLIST BODY...)" - (declare (indent 1) (debug if-let)) + (declare (indent 1) (debug if-let*)) (list 'if-let bindings (macroexp-progn body))) (defalias 'if-let 'if-let*) (defalias 'when-let 'when-let*) -(defalias 'and-let* 'when-let*) + +(defmacro and-let* (varlist &rest body) + "Bind variables according to VARLIST and conditionally eval BODY. +Like `when-let*', except if BODY is empty and all the bindings +are non-nil, then the result is non-nil." + (declare (indent 1) (debug when-let*)) + ;; `(when-let* ,varlist ,@(or body '(t))) + (if varlist + `(let* ,(setq varlist (internal--build-bindings varlist)) + (if ,(caar (last varlist)) + ,@(or body `(,(caar (last varlist)))))) + `(let* () ,@(or body '(t))))) (defsubst hash-table-empty-p (hash-table) "Check whether HASH-TABLE is empty (has 0 elements)."