Re: Accumulator syntax breaks precedence
Kevin Reid <kpreid-M/[email protected]>
| Newsgroups | gmane.comp.lang.e.general |
|---|---|
| Message-ID | <[email protected]> |
On Jan 31, 2011, at 20:47, Mark S. Miller wrote: > On Mon, Jan 31, 2011 at 5:41 PM, Kevin Reid <kpreid-M/[email protected]> > wrote: > >> The accumulator syntax effectively forces the leftmost operator to be >> lowest-precedence. This seems Very Surprising. >> >> I'm mentally filing this as yet another reason the accumulator syntax >> needs to be killed and replaced with something less special; any >> disagreement? > > No disagreement. That's why it's still off by default. What > replacements do > you have in mind? The reason the accumulator syntax is so hard to replace is that it provides *both* customizable accumulation *and* customizable iteration. Note that I, at least, have almost never used accum's flexibility to accumulate from within multiple loops, or to use 'while' or 'if'. Therefore my working hypothesis is that it's not worth having syntax for those cases. I would be inclined to replace it with something like series (as you already implemented), or stream operators (once I have streams designed to my satisfaction; I've recently been trying to finish that job). I once had the idea of replacing the accumulation part of 'accum' with an object which would define the accumulation operation and could be used within the accumulator, but it turned out to be annoyingly verbose; but perhaps something can be rescued from it. Here is the old draft message I wrote in 2005 and never posted: ------------------------------------------------------------------------ The experimental accumulator syntax, enabled by pragma.enable("accumulator") is, in my opinion, ugly. For simple cases, it is verbose, and for more complex uses the restriction of the loop body to "_.verb(...)" is inconvenient. Reference example: accum [] for item in 1..10 { _.with(item ** 2) } First, I propose an accumulator syntax that is not hardwired to loops and the magic _ variable/statement: accum out from [] { # accumulator syntax for item in 1..10 { # normal loop syntax out(item ** 2) # normal call syntax on an object } # defined by the accum ... } This expands into a local binding of 'out' to an object which is only usable in the dynamic scope, much as 'escape' does primitively. 'out' always calls the accumulated value's "with" method. This is not a severe limitation, as the initial value ([]) can be a custom object. To allow the value to be 'resolved' into the non-wrapped desired result, the result of the accumulation is accmulated-value.snapshot(), which happens to be identity for collections. Properties of this 'use a custom object' notion: (+) initial-value and means-of-accumulation become bundled in a single reference (-) the objects must be defined, which is more verbose than a single use, and requires them to be named or inlined I suspect that the former may be a worthwhile advantage, as it means that often-reused accumulation types become named objects as opposed to patterns of duplicated code. One-time cases could be simplified by a standard function: ? def accumBy(value, verb) { > return def accumulation { > to snapshot() { return value } > match [=="with", args] { > return accumBy(E.call(value, verb, args), verb) } > } > } # value <accumBy> ? accum out from accumBy("", "add") { for s in ["abc", "def"] { > out(s) } } # value: "abcdef" Um. The existing form of this is: accum "" for s in ["abc", "def"] { _ + s } I seem to have produced a non-simplification. Supposing a custom accumulator that ignores the first argument to 'with', we could perhaps write: ? accum out from stringConcatAccum { ["abc", "def"].iterate(out) } but this is still much longer than the original. -- Kevin Reid <http://switchb.org/kpreid/>