From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Stefan Monnier Newsgroups: gmane.emacs.devel Subject: Re: "Like `let*' but ....." Date: Wed, 25 Jan 2017 00:08:01 -0500 Message-ID: References: <20170124211227.GC7358@acm> <87lgu0qcks.fsf@web.de> NNTP-Posting-Host: blaine.gmane.org Mime-Version: 1.0 Content-Type: text/plain X-Trace: blaine.gmane.org 1485320965 24306 195.159.176.226 (25 Jan 2017 05:09:25 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Wed, 25 Jan 2017 05:09:25 +0000 (UTC) User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/26.0.50 (gnu/linux) To: emacs-devel@gnu.org Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Wed Jan 25 06:09:21 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 1cWFpe-0005kQ-Cw for ged-emacs-devel@m.gmane.org; Wed, 25 Jan 2017 06:09:18 +0100 Original-Received: from localhost ([::1]:57447 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cWFpj-0000Su-AZ for ged-emacs-devel@m.gmane.org; Wed, 25 Jan 2017 00:09:23 -0500 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:52233) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1cWFpC-0000Sb-31 for emacs-devel@gnu.org; Wed, 25 Jan 2017 00:08:51 -0500 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1cWFp8-0002Mf-Og for emacs-devel@gnu.org; Wed, 25 Jan 2017 00:08:50 -0500 Original-Received: from [195.159.176.226] (port=45965 helo=blaine.gmane.org) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_128_CBC_SHA1:16) (Exim 4.71) (envelope-from ) id 1cWFp8-0002Lr-Hg for emacs-devel@gnu.org; Wed, 25 Jan 2017 00:08:46 -0500 Original-Received: from list by blaine.gmane.org with local (Exim 4.84_2) (envelope-from ) id 1cWFor-0001sh-Od for emacs-devel@gnu.org; Wed, 25 Jan 2017 06:08:29 +0100 X-Injected-Via-Gmane: http://gmane.org/ Original-Lines: 67 Original-X-Complaints-To: usenet@blaine.gmane.org Cancel-Lock: sha1:7yV/TIXTfV6A5nLRoMAAILljrB0= X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 195.159.176.226 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:211591 Archived-At: > Those highly nested expressions come from destructuring. > I think the expansion is nearly as effecient as it could be. There's definitely room for improvement. Some of it would be easier/cleaner to fix in the byte-compiler than in the pcase macro. The most costly part is the use of (funcall pcase-N ...). Such forms are used to avoid duplicating the body of a branch (in the case of `pcase-let` that means duplicating the body of the `pcase-let`), so they're important to avoid potential code size blow up, but they impose a significant performance cost. Luckily, in many cases we can avoid them (e.g. when the body is small, or when the patterns are simple enough that they don't lead to any duplication at all). BTW, regarding the big pcase-let* in byte-compile-file-form-defalias, it was partly an experiment in the use of pcase patterns. OT1H I'm not convinced the result speaks very much in favor of pcase, OTOH if you try to rewrite this code without pcase it's not pretty either. I'll read it for you: ;; `macro' is non-nil if it defines a macro. ;; `fun' is the function part of `arg' (defaults to `arg'). (((or (and (or `(cons 'macro ,fun) `'(macro . ,fun)) (let macro t)) (and (let fun arg) (let macro nil))) arg) This part binds two vars: `fun` and `macro`. Basically, it binds `fun` to the value of `arg` except that if `arg` is a "macro value", `fun` gets the value of the macro's function (and `macro` gets value t rather than nil). ;; `lam' is the lambda expression in `fun' (or nil if not ;; recognized). ((or `(,(or `quote `function) ,lam) (let lam nil)) fun) This only binds `lam`. It takes the `fun` apart and extracts a lambda expression from it (or nil if it can't). ;; `arglist' is the list of arguments (or t if not recognized). ;; `body' is the body of `lam' (or t if not recognized). ((or `(lambda ,arglist . ,body) ;; `(closure ,_ ,arglist . ,body) (and `(internal-make-closure ,arglist . ,_) (let body t)) (and (let arglist t) (let body t))) lam)) This tries to take apart `lam` and extract two parts: `arglist` and `body`. The complexity here is that `arg` doesn't hold a "macro value" (i.e. something of the form (macro . FUN)), but instead it holds an expression that will return a macro value. So `arg` can be of the form (quote (macro . FUN)) (cons 'macro 'FUN) (cons 'macro #'FUN) (cons 'macro (internal-make-closure ...)) ... and of course FUN is usually of the form (lambda ...) but it can also be a plain symbol, or a # object or god knows what else. Stefan