unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#58278: Add new function seq-keep
@ 2022-10-03 21:30 Jonas Bernoulli
  2022-10-03 23:47 ` Lars Ingebrigtsen
  0 siblings, 1 reply; 16+ messages in thread
From: Jonas Bernoulli @ 2022-10-03 21:30 UTC (permalink / raw)
  To: 58278

While I still appreciate the `dash' package, I try to avoid it in
a package when all or most of its used `dash' functions and macros,
can be replaced with equivalent functions/macros from `seq', `cl-lib'
or other parts of Emacs.

Unfortunately I cannot find a replacement for `-keep', which I have been
using a lot.  I propose that we add something like:

  (cl-defgeneric seq-keep (pred sequence)
    "Return a list of all non-nil results of (PRED element) for elements in SEQUENCE."
    (delq nil (seq-map (lambda (elt) (funcall pred elt))
                       sequence)))

Cheers,
Jonas





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

* bug#58278: Add new function seq-keep
  2022-10-03 21:30 bug#58278: Add new function seq-keep Jonas Bernoulli
@ 2022-10-03 23:47 ` Lars Ingebrigtsen
  2022-10-04 10:05   ` Robert Pluim
  2022-10-04 12:50   ` Jonas Bernoulli
  0 siblings, 2 replies; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-03 23:47 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: 58278

Jonas Bernoulli <jonas@bernoul.li> writes:

> Unfortunately I cannot find a replacement for `-keep', which I have been
> using a lot.  I propose that we add something like:
>
>   (cl-defgeneric seq-keep (pred sequence)
>     "Return a list of all non-nil results of (PRED element) for elements in SEQUENCE."
>     (delq nil (seq-map (lambda (elt) (funcall pred elt))
>                        sequence)))

Hm...  well, here PRED isn't a predicate, really, but a transforming
function?  But you wish to filter out the nil results of that
transforming function.

That sounds useful -- there's more than a 100 matches for "delq
nil.*map" in-tree only -- but it's slightly confusing that the function
isn't altogether a predicate, but only kinda.  Would a function
signature like

(cl-defgeneric seq-keep (function sequence &optional pred)
  ...)

make more sense for this combination of map/filter?  (The default
predicate would, of course, be "not null".)





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

* bug#58278: Add new function seq-keep
  2022-10-03 23:47 ` Lars Ingebrigtsen
@ 2022-10-04 10:05   ` Robert Pluim
  2022-10-04 10:13     ` Lars Ingebrigtsen
  2022-10-04 12:50   ` Jonas Bernoulli
  1 sibling, 1 reply; 16+ messages in thread
From: Robert Pluim @ 2022-10-04 10:05 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 58278, Jonas Bernoulli

>>>>> On Tue, 04 Oct 2022 01:47:59 +0200, Lars Ingebrigtsen <larsi@gnus.org> said:

    Lars> Jonas Bernoulli <jonas@bernoul.li> writes:
    >> Unfortunately I cannot find a replacement for `-keep', which I have been
    >> using a lot.  I propose that we add something like:
    >> 
    >> (cl-defgeneric seq-keep (pred sequence)
    >> "Return a list of all non-nil results of (PRED element) for elements in SEQUENCE."
    >> (delq nil (seq-map (lambda (elt) (funcall pred elt))
    >> sequence)))

    Lars> Hm...  well, here PRED isn't a predicate, really, but a transforming
    Lars> function?  But you wish to filter out the nil results of that
    Lars> transforming function.

    Lars> That sounds useful -- there's more than a 100 matches for "delq
    Lars> nil.*map" in-tree only -- but it's slightly confusing that the function
    Lars> isn't altogether a predicate, but only kinda.  Would a function
    Lars> signature like

    Lars> (cl-defgeneric seq-keep (function sequence &optional pred)
    Lars>   ...)

    Lars> make more sense for this combination of map/filter?  (The default
    Lars> predicate would, of course, be "not null".)

How is this different from 'cl-mapcan'? (apart from the syntactic sugar)

Robert
-- 





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

* bug#58278: Add new function seq-keep
  2022-10-04 10:05   ` Robert Pluim
@ 2022-10-04 10:13     ` Lars Ingebrigtsen
  2022-10-04 10:27       ` Robert Pluim
  0 siblings, 1 reply; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-04 10:13 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 58278, Jonas Bernoulli

Robert Pluim <rpluim@gmail.com> writes:

> How is this different from 'cl-mapcan'? (apart from the syntactic sugar)

I don't see how seq-keep would resemble cl-mapcan much?





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

* bug#58278: Add new function seq-keep
  2022-10-04 10:13     ` Lars Ingebrigtsen
@ 2022-10-04 10:27       ` Robert Pluim
  2022-10-04 10:42         ` Lars Ingebrigtsen
  0 siblings, 1 reply; 16+ messages in thread
From: Robert Pluim @ 2022-10-04 10:27 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 58278, Jonas Bernoulli

>>>>> On Tue, 04 Oct 2022 12:13:55 +0200, Lars Ingebrigtsen <larsi@gnus.org> said:

    Lars> Robert Pluim <rpluim@gmail.com> writes:
    >> How is this different from 'cl-mapcan'? (apart from the syntactic sugar)

    Lars> I don't see how seq-keep would resemble cl-mapcan much?

Well, cl-mapcan applies a function to the elements of a sequence and
discards 'nil' results. Looks pretty similar to me.

Robert
-- 





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

* bug#58278: Add new function seq-keep
  2022-10-04 10:27       ` Robert Pluim
@ 2022-10-04 10:42         ` Lars Ingebrigtsen
  2022-10-04 10:50           ` Robert Pluim
  0 siblings, 1 reply; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-04 10:42 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 58278, Jonas Bernoulli

Robert Pluim <rpluim@gmail.com> writes:

> Well, cl-mapcan applies a function to the elements of a sequence and
> discards 'nil' results. Looks pretty similar to me.

No, it concatenates the results, so the values returned by the function
has to be lists.

But, yes, if you return lists, then nil return values will "disappear".





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

* bug#58278: Add new function seq-keep
  2022-10-04 10:42         ` Lars Ingebrigtsen
@ 2022-10-04 10:50           ` Robert Pluim
  2022-10-04 11:10             ` Lars Ingebrigtsen
  0 siblings, 1 reply; 16+ messages in thread
From: Robert Pluim @ 2022-10-04 10:50 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 58278, Jonas Bernoulli

>>>>> On Tue, 04 Oct 2022 12:42:50 +0200, Lars Ingebrigtsen <larsi@gnus.org> said:

    Lars> Robert Pluim <rpluim@gmail.com> writes:
    >> Well, cl-mapcan applies a function to the elements of a sequence and
    >> discards 'nil' results. Looks pretty similar to me.

    Lars> No, it concatenates the results, so the values returned by the function
    Lars> has to be lists.

Thatʼs why I said "apart from the syntactic sugar" 😀

Robert
-- 





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

* bug#58278: Add new function seq-keep
  2022-10-04 10:50           ` Robert Pluim
@ 2022-10-04 11:10             ` Lars Ingebrigtsen
  2022-10-04 11:21               ` Robert Pluim
  0 siblings, 1 reply; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-04 11:10 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 58278, Jonas Bernoulli

Robert Pluim <rpluim@gmail.com> writes:

> Thatʼs why I said "apart from the syntactic sugar" 😀

Having to rewrite

(seq-keep #'cl-digit-char-p '(?6 ?a))
=> (6)

to

(cl-mapcan (lambda (c)
	     (let ((res (cl-digit-char-p c)))
	       (and res (list res))))
	   '(?6 ?a))
=> (6)

is more than "syntactic sugar" in my book.  Nobody would want to write
code like the latter.





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

* bug#58278: Add new function seq-keep
  2022-10-04 11:10             ` Lars Ingebrigtsen
@ 2022-10-04 11:21               ` Robert Pluim
  2022-10-04 11:23                 ` Lars Ingebrigtsen
  0 siblings, 1 reply; 16+ messages in thread
From: Robert Pluim @ 2022-10-04 11:21 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 58278, Jonas Bernoulli

>>>>> On Tue, 04 Oct 2022 13:10:38 +0200, Lars Ingebrigtsen <larsi@gnus.org> said:

    Lars> Robert Pluim <rpluim@gmail.com> writes:
    >> Thatʼs why I said "apart from the syntactic sugar" 😀

    Lars> Having to rewrite

    Lars> (seq-keep #'cl-digit-char-p '(?6 ?a))
    Lars> => (6)

    Lars> to

    Lars> (cl-mapcan (lambda (c)
    Lars> 	     (let ((res (cl-digit-char-p c)))
    Lars> 	       (and res (list res))))
    Lars> 	   '(?6 ?a))
    Lars> => (6)

    Lars> is more than "syntactic sugar" in my book.  Nobody would want to write
    Lars> code like the latter.

I never meant that. I meant defining `seq-keep' in terms of `'cl-mapcan',
with the appropriate converting elements to lists done for you (or
even using `mapcan' if youʼre willing to give up the &rest behaviour
of `cl-mapcan')

Robert
-- 





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

* bug#58278: Add new function seq-keep
  2022-10-04 11:21               ` Robert Pluim
@ 2022-10-04 11:23                 ` Lars Ingebrigtsen
  2022-10-04 11:37                   ` Robert Pluim
  0 siblings, 1 reply; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-04 11:23 UTC (permalink / raw)
  To: Robert Pluim; +Cc: 58278, Jonas Bernoulli

Robert Pluim <rpluim@gmail.com> writes:

> I never meant that. I meant defining `seq-keep' in terms of `'cl-mapcan',
> with the appropriate converting elements to lists done for you (or
> even using `mapcan' if youʼre willing to give up the &rest behaviour
> of `cl-mapcan')

Oh, OK.  I don't think that would be particularly efficient, though.





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

* bug#58278: Add new function seq-keep
  2022-10-04 11:23                 ` Lars Ingebrigtsen
@ 2022-10-04 11:37                   ` Robert Pluim
  0 siblings, 0 replies; 16+ messages in thread
From: Robert Pluim @ 2022-10-04 11:37 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 58278, Jonas Bernoulli

>>>>> On Tue, 04 Oct 2022 13:23:02 +0200, Lars Ingebrigtsen <larsi@gnus.org> said:

    Lars> Robert Pluim <rpluim@gmail.com> writes:
    >> I never meant that. I meant defining `seq-keep' in terms of `'cl-mapcan',
    >> with the appropriate converting elements to lists done for you (or
    >> even using `mapcan' if youʼre willing to give up the &rest behaviour
    >> of `cl-mapcan')

    Lars> Oh, OK.  I don't think that would be particularly efficient, though.

Iʼve measured it: itʼs not (even when using mapcan) :-)

Robert
-- 





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

* bug#58278: Add new function seq-keep
  2022-10-03 23:47 ` Lars Ingebrigtsen
  2022-10-04 10:05   ` Robert Pluim
@ 2022-10-04 12:50   ` Jonas Bernoulli
  2022-10-04 13:47     ` Lars Ingebrigtsen
  1 sibling, 1 reply; 16+ messages in thread
From: Jonas Bernoulli @ 2022-10-04 12:50 UTC (permalink / raw)
  To: Lars Ingebrigtsen; +Cc: 58278

Lars Ingebrigtsen <larsi@gnus.org> writes:

> Would a function signature like
>
> (cl-defgeneric seq-keep (function sequence &optional pred)
>   ...)
>
> make more sense for this combination of map/filter?  (The default
> predicate would, of course, be "not null".)

Yes, that would be an improvement.  Some (but certainly not all)
uses of dash's `-keep' look something like

  (-keep (lambda (elt)
           (and (symbolp elt)
                (symbol-name elt)))
         sequence)

and

  (seq-keep #'symbol-name sequence #'symbolp)

would be much nicer in those situations.

In at least some of those cases `mapcan' would work just as well
as `-keep', so after adding &optional PRED, `seq-keep' could also
be used in many places one would have reached for `mapcan' before,
making it even more useful.

I am unsure how I feel about it myself, but we should also consider

  (function pred sequence)

PRED wouldn't be optional then, but we should of course allow it to
be nil.  (Forcing the use of #'identity would not make sense, since
we want FUNCTION to serve both as a predicate and a transforming
function in that case.)

Concerning the argument order, in my opinion

  (seq-keep (lambda (elt)
              ...)
            (lambda (elt)
              ...)
            sequence)

looks better than

  (seq-keep (lambda (elt)
              ...)
            sequence
            (lambda (elt)
              ...))

because the variable named "sequence" looks out of place in the second
instance.  But of course all of FUNCTION, PRED and SEQUENCE can be just
a symbol or a more complex expression.  For instance if only PRED is
complex, then

  (seq-keep #'symbol-name sequence
            (lambda (elt)
               ...))

looks better than

  (seq-keep #'symbol-name
            (lambda (elt)
               ...)
            sequence)

So there is no order that is always best, from an aesthetic point
of view.  In my own use at least, most of the time either all three
arguments would be moderately complex expressions or only the two
functions arguments would complex and the sequence argument would be
just a variable. For that reason I would favor the two functions to
be placed next to each other, I think.

The (function pred sequence) argument list has the advantage that it
is in (reverse) "chronological" order.  First we have a sequence, then
we filter the elements, and finally we transform the elements that we
kept, at least conceptually.

Using actual chronological order (sequence pred function) is out of
question as that would conflict with all(?) other mapping functions;
as is (sequence [pred] function), I presume.

Just some food for thought; as of yet, I am unsure what order I
prefer myself -- though I lean towards (function pred sequence).
But if that is deemed unusual and thus undesirable, (function
sequence &optional pred) also works for me.





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

* bug#58278: Add new function seq-keep
  2022-10-04 12:50   ` Jonas Bernoulli
@ 2022-10-04 13:47     ` Lars Ingebrigtsen
  2022-10-04 13:56       ` Lars Ingebrigtsen
  0 siblings, 1 reply; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-04 13:47 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: 58278

Jonas Bernoulli <jonas@bernoul.li> writes:

> Yes, that would be an improvement.  Some (but certainly not all)
> uses of dash's `-keep' look something like
>
>   (-keep (lambda (elt)
>            (and (symbolp elt)
>                 (symbol-name elt)))
>          sequence)
>
> and
>
>   (seq-keep #'symbol-name sequence #'symbolp)
>
> would be much nicer in those situations.

Hm...  That's not exactly what I was thinking here.  I was thinking

(cl-defgeneric seq-keep (func sequence &optional pred)
  (if pred
      (seq-filter pred (seq-mapcar func sequence))
    (delq nil (seq-mapcar func sequence))))

which is the traditional "keep" semantics, but allows extending the
concept of "keep" to more than "is non-nil".

But that may well be an overcomplication -- in the unusual cases where
it's not nil that people want to keep, they can just type

  (seq-filter pred (seq-mapcar func sequence))

themselves, which has very clear semantics.

So I think, on second consideration, I'd rather just go with

(cl-defgeneric seq-keep (func sequence)
  (delq nil (seq-mapcar func sequence)))

like you originally suggested (but with just an argument name change).





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

* bug#58278: Add new function seq-keep
  2022-10-04 13:47     ` Lars Ingebrigtsen
@ 2022-10-04 13:56       ` Lars Ingebrigtsen
  2022-10-04 13:59         ` Lars Ingebrigtsen
  0 siblings, 1 reply; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-04 13:56 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: 58278

Just for kicks, here's some random "del.*map" instances from the
Emacs sources:

(delq nil (mapcar (lambda (n) (and (>= n 0) n)) articles))

This should be (seq-filter #'cl-plusp articles).

(delq nil (mapcar #'gnus-server-to-method gnus-agent-covered-methods))

This would be nice as seq-keep.

      (delq nil (mapcar
                 (lambda (c)
                   (when (string-prefix-p base c)
                     (substring c base-size)))
                 hist)))))

Ditto.

   (delq nil (mapcar (lambda (action)
                       (cond
                        ((eq action 'create) 'created)
                        ((eq action 'modify) 'changed)
                        ((eq action 'attrib) 'attribute-changed)
                        ((memq action '(delete delete-self move-self)) 'deleted)
                        ((eq action 'moved-from) 'renamed-from)
                        ((eq action 'moved-to) 'renamed-to)
                        ((eq action 'ignored) 'stopped)))
                     actions))

Ditto.

     (delq nil (mapcar
		(lambda (x) (if (string-match "\\`\\." x) x))
		ido-temp-list)))

This should be seq-filter.

			(cookies (delq nil (mapcar
					    (lambda (e)
					      (org-list-get-checkbox e s))
					    items))))

seq-keep.

    (let* ((have (delq nil (mapcar
			    (lambda (x) (get-text-property 1 'time-of-day x))
			    list)))

seq-keep.

          (string-join
           (delq nil (mapcar
                      (lambda (item)
                        (when (cdr item)
                          (format "%s='%s'" (car item) (cdr item))))
                      `(("type" . ,type) ("sender" . ,sender)
                        ("destination" . ,destination) ("path" . ,path)
                        ("interface" . ,interface) ("member" . ,member))))
           ",")

seq-keep.

       (reverse (delete "" (mapcar (lambda (r)
				     (replace-regexp-in-string "nil" "" r))
				   result0)))))))

This suggest that the signature should be

(func sequence &optional delete-element)

which defaults to nil, but could be "" here, and use seq-keep.

  (delq 'type (mapcar #'car (haiku-selection-data clipboard nil))))

Ditto.







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

* bug#58278: Add new function seq-keep
  2022-10-04 13:56       ` Lars Ingebrigtsen
@ 2022-10-04 13:59         ` Lars Ingebrigtsen
  2022-10-04 19:46           ` Lars Ingebrigtsen
  0 siblings, 1 reply; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-04 13:59 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: 58278

Lars Ingebrigtsen <larsi@gnus.org> writes:

> This suggest that the signature should be
>
> (func sequence &optional delete-element)
>
> which defaults to nil, but could be "" here, and use seq-keep.

But that gets us into problems w.r.t. the comparison function -- we can
use delq here for "", but not for "foo", which seems inconsistent.

So...  we're back to the (func sequence) as the signature.





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

* bug#58278: Add new function seq-keep
  2022-10-04 13:59         ` Lars Ingebrigtsen
@ 2022-10-04 19:46           ` Lars Ingebrigtsen
  0 siblings, 0 replies; 16+ messages in thread
From: Lars Ingebrigtsen @ 2022-10-04 19:46 UTC (permalink / raw)
  To: Jonas Bernoulli; +Cc: 58278

Lars Ingebrigtsen <larsi@gnus.org> writes:

> So...  we're back to the (func sequence) as the signature.

So I've now added this to Emacs 29.





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

end of thread, other threads:[~2022-10-04 19:46 UTC | newest]

Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-10-03 21:30 bug#58278: Add new function seq-keep Jonas Bernoulli
2022-10-03 23:47 ` Lars Ingebrigtsen
2022-10-04 10:05   ` Robert Pluim
2022-10-04 10:13     ` Lars Ingebrigtsen
2022-10-04 10:27       ` Robert Pluim
2022-10-04 10:42         ` Lars Ingebrigtsen
2022-10-04 10:50           ` Robert Pluim
2022-10-04 11:10             ` Lars Ingebrigtsen
2022-10-04 11:21               ` Robert Pluim
2022-10-04 11:23                 ` Lars Ingebrigtsen
2022-10-04 11:37                   ` Robert Pluim
2022-10-04 12:50   ` Jonas Bernoulli
2022-10-04 13:47     ` Lars Ingebrigtsen
2022-10-04 13:56       ` Lars Ingebrigtsen
2022-10-04 13:59         ` Lars Ingebrigtsen
2022-10-04 19:46           ` Lars Ingebrigtsen

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