help-gnu-emacs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: How to create a higher order function?


From: Marcin Borkowski
Subject: Re: How to create a higher order function?
Date: Fri, 24 Sep 2021 10:57:53 +0200
User-agent: mu4e 1.1.0; emacs 28.0.50

On 2021-09-22, at 21:03, Stefan Monnier via Users list for the GNU Emacs text 
editor <help-gnu-emacs@gnu.org> wrote:

> 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))))

Interesting, I didn't think of this.

>> But maybe (B) is better under some circumstances?
>
> I'm hoping B can be banned at some point in the future ;-)

This is great news, since I read it "don't bother with it". :-)

>> 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).

Thanks for your detailed answer!  As usual, it turns out that there's
always so much to learn!

Best,

-- 
Marcin Borkowski
http://mbork.pl



reply via email to

[Prev in Thread] Current Thread [Next in Thread]