From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Stefan Monnier via Users list for the GNU Emacs text editor Newsgroups: gmane.emacs.help Subject: Re: How to create a higher order function? Date: Wed, 22 Sep 2021 15:03:42 -0400 Message-ID: References: <87k0jawotx.fsf@mbork.pl> Reply-To: Stefan Monnier Mime-Version: 1.0 Content-Type: text/plain Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="13786"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) To: help-gnu-emacs@gnu.org Cancel-Lock: sha1:Wq9G5AJ7MXph7GdAREXfwrtnPWo= Original-X-From: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane-mx.org@gnu.org Wed Sep 22 21:31:09 2021 Return-path: Envelope-to: geh-help-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1mT7xU-0003Rp-Ej for geh-help-gnu-emacs@m.gmane-mx.org; Wed, 22 Sep 2021 21:31:08 +0200 Original-Received: from localhost ([::1]:40964 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1mT7xT-0000V7-8b for geh-help-gnu-emacs@m.gmane-mx.org; Wed, 22 Sep 2021 15:31:07 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:55028) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mT7XD-0007cn-Km for help-gnu-emacs@gnu.org; Wed, 22 Sep 2021 15:03:59 -0400 Original-Received: from ciao.gmane.io ([116.202.254.214]:57932) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1mT7X6-0001Al-01 for help-gnu-emacs@gnu.org; Wed, 22 Sep 2021 15:03:57 -0400 Original-Received: from list by ciao.gmane.io with local (Exim 4.92) (envelope-from ) id 1mT7X3-0008z0-G6 for help-gnu-emacs@gnu.org; Wed, 22 Sep 2021 21:03:49 +0200 X-Injected-Via-Gmane: http://gmane.org/ Received-SPF: pass client-ip=116.202.254.214; envelope-from=geh-help-gnu-emacs@m.gmane-mx.org; helo=ciao.gmane.io X-Spam_score_int: -16 X-Spam_score: -1.7 X-Spam_bar: - X-Spam_report: (-1.7 / 5.0 requ) BAYES_00=-1.9, HEADER_FROM_DIFFERENT_DOMAINS=0.249, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: help-gnu-emacs@gnu.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Users list for the GNU Emacs text editor List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: help-gnu-emacs-bounces+geh-help-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: "help-gnu-emacs" Xref: news.gmane.io gmane.emacs.help:133150 Archived-At: > (defun negate (fun) > "Return a function returning the logical opposite of FUN." > `(lambda (&rest args) > (not (apply ,(symbol-function fun) args)))) This will fail when `fun` is not a function name but a (lambda ...). It will also fail when `fun` is a function alias (hence (symbol-function fun) returns the name of another function). It will also fail when `fun` is a symbol whose content is an interpreted lexically scoped function (hence (symbol-function fun) returns something of the form (closure ...)). It will also fail when `fun` is an autoloaded function that's not yet loaded (hence (symbol-function fun) returns something of the form (autoload ...)). I think what you meant was (defun negate (fun) "Return a function returning the logical opposite of FUN." `(lambda (&rest args) (not (apply ',fun args)))) > But maybe (B) is better under some circumstances? I'm hoping B can be banned at some point in the future ;-) > Is it faster? I don't think so. Currently closures constructed in lexical-binding mode are not super efficient (back in Emacs-24, the focus was on providing lexical-scoping with clean semantics and without breaking or slowing down dynamic scoping. Efficiency of lexical-binding was secondary, and we haven't really attacked that yet). More specifically, constructing a closure will allocate two new vectors (whereas the ideal would be 1 vector), and one of them holds a lot more than the set of free variables (it also holds all the constants used in the code, such as the names of all the functions it calls). But the above construction of a (lambda ...) list to mimic a true closure isn't very efficient either: if I count correctly it will need to allocate 9 new cons cells. Which is currently faster, I don't know. But if the construction of the true closure is slower, at least there's the theoretical possibility to invest implementation efforts into making it more efficient by using a more conventional closure representation. As for efficiency when calling the constructed function, I'm pretty sure that C will be significantly faster (tho you'll have to call them many times to see the difference ;-), but I suspect that in practice for this specific example the difference may not be very large because most of the time will be spent processing the `&rest` (i.e. converting the args (stored in a vector) into a list) and the `apply` (i.e. converting the list back to a vector), and the benchmark will likely show that you're spending a lot of time in the GC (because of the need to recover all those temporary lists generated by the `&rest`). So to better see the effect you might want to use something like: (defun negate (fun) "Return a function returning the logical opposite of FUN." (lambda (arg1 arg2) (not (funcall fun arg1 arg2)))) where I'd expect the (C) version to be faster by a quite significant margin (like more than a factor 2). Stefan