unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Functional composition in ELisp: add `compose' function?
@ 2021-02-15  1:39 Stefan Kangas
  2021-02-15  3:02 ` Stefan Monnier
  0 siblings, 1 reply; 2+ messages in thread
From: Stefan Kangas @ 2021-02-15  1:39 UTC (permalink / raw)
  To: emacs-devel

I often miss functional composition when I code Emacs Lisp, to say
things like:

    (seq-filter (compose #'not #'stringp) '("a" "b" 1 2))
    => (1 2)

Here's an example definition:

    (defun compose (&rest fns)
      (cl-destructuring-bind (fun . rest) (reverse fns)
        (lambda (&rest args)
          (seq-reduce (lambda (v f) (funcall f v))
                      rest
                      (apply fun args)))))

There is at least some demand for it: the popular third-party library
dash.el provides it[1].  It also exists in Scheme[2] and Common Lisp[3].

Could we add this to Emacs Lisp?

Footnotes:
[1]  https://github.com/magnars/dash.el#-compose-rest-fns

[2]  https://www.gnu.org/software/guile/manual/html_node/Higher_002dOrder-Functions.html

[3]  https://common-lisp.net/project/cl-utilities/doc/compose.html



^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: Functional composition in ELisp: add `compose' function?
  2021-02-15  1:39 Functional composition in ELisp: add `compose' function? Stefan Kangas
@ 2021-02-15  3:02 ` Stefan Monnier
  0 siblings, 0 replies; 2+ messages in thread
From: Stefan Monnier @ 2021-02-15  3:02 UTC (permalink / raw)
  To: Stefan Kangas; +Cc: emacs-devel

> Here's an example definition:
>
>     (defun compose (&rest fns)
>       (cl-destructuring-bind (fun . rest) (reverse fns)
>         (lambda (&rest args)
>           (seq-reduce (lambda (v f) (funcall f v))
>                       rest
>                       (apply fun args)))))

LGTM (tho I'd use `pcase-let` instead of `cl-destructuring-bind`, of
course).

Note that, sadly, you can use `nreverse` up there.

Note, also sadly, that

    (compose #'not #'stringp)

will be significantly less efficient than

    (lambda (x) (not (stringp x)))

So we definitely should accompany it with a compiler-macro, which should
be able to macro-expand it to something equivalent to

    (lambda (&rest args) (not (apply #'stringp args)))

but note that it's still significantly less efficient than

    (lambda (x) (not (stringp x)))

which I find personally quite readable.  I wish the byte-compiler was
able to turn

    (lambda (&rest args) (not (apply #'stringp args)))

into

    (lambda (x) (not (stringp x)))

[ Among other things, I believe it could improve the efficiency of
  `cl-generic.el` function calls/dispatch.  ]
but it seems difficult/dangerous to do in general.


        Stefan




^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2021-02-15  3:02 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-15  1:39 Functional composition in ELisp: add `compose' function? Stefan Kangas
2021-02-15  3:02 ` Stefan Monnier

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).