Closed shawwn closed 5 years ago
I also had an idea related to accum
. I've updated it to work like this:
arc> (each x (obj a 1 b 2) (out x))
'((b 2) (a 1))
arc> (each (k v) (obj a 1 b 2) (out k v))
'((b 2) (a 1))
And calling the accum function with 0 arguments will return all the currently-accumulated values (and reset the accumulator).
This seems like what you'd always want, as a user.
To clarify what I mean:
arc> (accum a (a 1) (a 1 2) (a 1 2 3))
'(1 (1 2) (1 2 3))
arc> (accum a (a 1) (a 1 2) (a 1 2 3) (prn (a)) (a 'reset))
(1 (1 2) (1 2 3))
'(reset)
Seems interesting, and I see it adds functionality without really breaking anything. (I don't think people rely on the result of each
.) Ship it!
When I saw you write (out (list x y))
, it crossed my mind that it's a good thing you didn't do that with (out x y)
, since that would mean (apply out xs)
should accumulate the list xs
, and therefore (out x)
should accumulate a list containing x
.
I thought about it for a second and settled on the idea that if (apply out xs)
meant anything, it would mean "accumulate each of the elements of the list xs
in some order".
Then I kept reading and you did use (out x y)
as a shorthand for (out:list x y)
after all. Couldn't these different behaviors for zero arguments, one argument, and two arguments have used different names? And isn't the name out:list
pretty concise already?
And calling the accum function with 0 arguments will return all the currently-accumulated values (and reset the accumulator).
This seems like what you'd always want, as a user.
That makes the state non-monotonic, which is pretty surprising to me since I associate accum
with append-only list generation. Programming in Arc and finding out that so much of my code could use an append-only style and become simpler as a result was very satisfying.
When I was excited that adding accum
functionality to each
could make each
more compositional, it was mostly because I was pondering how this would be extrapolated to channels or coroutines. The operation "unsend all the messages that have been sent so far" is clearly not a very viable operation for channels or coroutines, so, so much for that. XD
The operation you describe is familiar to me, though. In some of my side-effectful JavaScript code, I've sometimes written operations that wipe out the current accumulation state and add that list of values to another list. I call them bank
, like what they shout on The Weakest Link. :-p This usually happens when I'm looping over one list and building a list of lists out of it.
Incidentally, I think each
would be a better design if out
wasn't an anaphoric variable. You said writing (each a x xs ...)
would be ugly, but I disagree, especially if the new functionality uses a new name like (accum-each a x xs ...)
. I think it'll be common to want to use out
from inside multiple nested loops (since that becomes monadic composition of the lists looped over this way), but that's cumbersome to do when each loop shadows the binding of out
. Writing (let acc out ...)
to avoid unwanted shadowing is at least as cumbersome as writing (accum acc ...)
in the first place.