:) Yeah, that's a nice example where infix-with-precedence looks nicer than curly infix (without precedence). http://sourceforge.net/p/readable/wiki/Rationale points out that precedence breaks homoiconicity. And without precedence you end up with a lot more redundant whitespace and tokens to do nested infix. Hmm, perhaps if the infix tokens are limited (Nulan's idea http://arclanguage.org/item?id=16487), violating homoiconicity for just them may be more reasonable. What if user code can extend and locally override the infix ops, but not change their relative precedence? I'm going to look for more examples from numerical methods and graphics.
Also, I think you underestimate how generally useful perform can be :) What if I called it poly for polynomial? I'll keep an eye out for more examples. Adding precedence doesn't change how uniform complex expressions have to look if you can't group them. It isn't as big a deal here, but I think more complex expressions with the infix macro would get less readable. What I really want is to use juxtaposition to indicate higher precedence:
(+ b.p a.q a.p)
---
Whoa, whacky idea alert. What if we use whitespace to indicate operator precedence?
(fib-iter {b * q + a * q + a * p}
{b * p + a * q}
p
q
{n - 1})
Here the + operators have three spaces rather than one around them, so are at a lower precedence and get translated into (+ (* b q) (+ (* a q) (* a p))). Assume that operators at the same precedence are always applied right-associatively.
Whoa, whacky idea alert. What if we use whitespace to indicate operator precedence?
Ha! File that under "never would've thought of it". Still think prefix does just fine, but I like that idea for its quirkiness.
Also, I think you underestimate how generally useful perform can be :)
Superficially contemplating perform (namely the fact that it's a macro) made me think of one thing I wish I had while writing infix. pop is a macro, so I couldn't pass it to map, proper. What I needed was a macro to map macros:
; Goofy-looking name, but bear with me
(mac macmap (m . exprs)
`(list ,@(map [list m _] exprs)))
(push (macmap pop ops (cdr prefix) prefix) prefix)
Which got me thinking: why did perform need to be a macro again? Well, obviously
(sum [apply * _] (list (q q) (2 p q)))
tries to eval (q q) and (2 p q), and writing (list q q) defeats the purpose of brevity. (Side note: in vanilla Arc, you couldn't use q.q, because ssyntax isn't expanded before macros.)
Then I actually double-checked your original definition of perform and realized (macmap pop ...) = (perform list pop ...). So I've found my own example! But I think we might could do one better.
What if I called it poly for polynomial?
poly is too specific, if this operator hopes to be general. The operation itself smacks more of distributivity---almost like distributing an operator over cons. Emphasis on "an" operator, not a pair of them (lest it read like "distribute addition over multiplication"). But because (macmap ...) = (perform list ...), maybe it's just a better name for macmap:
(mac distribute (op . exprs)
`(list ,@(map [list op _] exprs)))
; Thus
(distribute pop ops (cdr prefix) prefix)
If we were to make perform a single-operator macro, a similarity I should've noticed earlier appears: it's almost the same as macmap, except
(mac distribute (op . exprs)
`(list ,@(map [cons op _] exprs))) ; cons vs list!
; Thus
(apply + (distribute * (q q) (2 p q)))
Not that the above is the best rewrite of the original, but if it were...is there a way to reconcile the cons vs list difference, whether by different names or by merging it into a super-distribute?
I don't have have much to contribute in response except tangents.
Well, birds of a feather...
1. Still, way too clever for my taste
Oh, certainly. It was a result of me golfing an earlier version. :)
6. Can I prevail on you to switch from zero to zero??
In a heartbeat. I wish Arc used question marks (judiciously, mind you; don't need names like Scheme's char<?). But it doesn't, so I kowtow to its conventions.
I've doodled this idea independently a couple of times, but I see a few issues:
1. Line breaks throw a monkey wrench in the works (though it might be reasonable to prohibit line breaks within { ... }).
2. In many contexts, it can be tough to count spaces. :)
3. Sometimes it's nice to tabulate similar lines of code using extra spaces, and in those cases this feature would be a minor annoyance, since it would force some subexpressions to bail out to parentheses.
// Horizontal layout interferes:
var wargle = 2 * x + 0.03 * y + 200;
var tricennarious = 13 * x + 0.4 * y + 50;
// Fix:
var wargle = 2 * x + (0.03 * y) + 200;
var tricennarious = 13 * x + (0.4 * y) + 50;
var wargle = 2 * x + 0.03 * y + 200;
var tricennarious = 13 * x + 0.4 * y + 50;
Adding tabulation in addition to whitespace precedence would end up making expressions even more loose and baggy than otherwise. The writer would have to count spaces, but it's fairly clean when reading.
---
Thanks for the pointers! I'm going to go look at those now.