Variant Of "COLLECT" Without "KEEP"

I was writing a PARSE example up with two COLLECTs in it, and I messed both of them up at first...

  • I expected collect some integer! to work, instead of collect some keep integer!.

  • I wrote collect keep some gather instead of collect some keep gather

So I can see the appeal of a KEEP-less COLLECT. But it's tough to implement cleanly; I don't think putting the COLLECT underneath an iteration and having it sneakily retain memory across those iterations is practical (though clever).

One line of attack in PARSE would be a construct that implies both iteration and collection together, so you could say something like collect-some-keep integer! Though that doesn't give you a way to express a difference of tolerating empty collections, you'd need collect-try-some-keep if you wanted that.

Maybe having a thing and calling it ACCUMULATE would be useful?

>> parse [hello 1 2 3] [let w: word! (print [w]), accumulate integer!]
hello
== [1 2 3]

It could have the at-least-one semantic, and then you could TRY ACCUMULATE and get a NULL if there weren't any (as opposed to an empty block). Then maybe you resort to COLLECT if you always wanted a block. Or vice-versa. :man_shrugging:

Maybe a variant like ACCUMULATE* could give back NULL if there's no YIELDs, e.g. the function it calls just returns NULL. (there's a COLLECT* that does this if there's no KEEPs.)

>> collect* [keep 1 keep 2]
== [1 2]

>> collect* [print "No keeps!"]
No keeps!
== ~null~  ; anti

A non-combinator ACCUMULATE could be applied to generators, as above:

>> accumulate generator [
      for x each [1 2] [yield x * 10] yield [a b] yield spread [d e]
   ]
== [10 20 [a b] d e]

If you passed ACCUMULATE a BLOCK! it could assume you wanted that block to be a generator:

>> accumulate [
      for x each [1 2] [yield x * 10] yield [a b] yield spread [d e]
   ]
== [10 20 [a b] d e]

Again, that's close to COLLECT and KEEP, minus the ability to KEEP/LINE or KEEP/PART or KEEP/DUP.