Arc Forumnew | comments | leaders | submitlogin
4 points by waterhouse 4867 days ago | link | parent

(I'm noticing there's a bit of a brevity boost with infix syntax, though. It means you typically only have to add "1 + " to an expression, rather than "(+ 1 " on one side and ")" on the other, for a total of one edit versus two. I guess that makes it a way to boost brevity in a less customizable language.

With ssyntax, you usually only have to add "inc:" or "inc." to the left side of an expression (depending on whether it's already a function/macro call or just a symbol). This is why I love the hell out of ssyntax. It only doesn't work if the expression is already of the form "a.b", in which case you have to add some parentheses. Currently, "inc:inc.2" expands to "(compose inc inc.2)".

Recommendation: Have "a:b.c" expand to (a:b c); this will make it always, or nearly always (I haven't thought much about using it with quote or quasiquote), possible to tack an extra function/macro call onto an expression with a single edit. I think it's also more consistent: currently we have a.b.c -> (a.b c) [-> ((a b) c)], which is useful for referencing nested data structures; and it fits that pattern to have a:b.c -> (a:b c) [-> ((compose a b) c) -> (a (b c))]. I really think this would be a big improvement.

Anyway, this ssyntax stuff has the major advantage that it works to tack on any single-argument function/macro, rather than just the very few that are important enough to have their own special character. I find this extremely convenient: I can add "time:" and "prn:" to an expression when I want to debug it, and then remove it just as easily. Combined with my 'cp function (http://arclanguage.org/item?id=12873), this has in my past made for some very pleasant debugging.

Aesthetically, tacking "func:" onto "expr" is like adding an element to the tree (in fact, it literally does "expr -> (list func expr) = (cons func (cons expr nil))"), which is an O(1) operation, and it makes sense for it to always be a simple O(1) editing operation. (Adding something to the left side, then remembering to look for the right side so you can add a close-paren, is not O(1) to me.) In fact, it's a common O(1) operation, and it should be O(1); and the same should go for its opposite, removing an element previously tacked on.

Imma go figure out how to change ac.scm. ...And I've kludged it by making . and ! expand before : and ~ in the definition of "expand-ssyntax" in ac.scm.

  ((or (insym? #\. sym) (insym? #\! sym)) expand-sexpr) ;switched order
  ((or (insym? #\: sym) (insym? #\~ sym)) expand-compose)
  --ac.scm
This should work fine for the near future, as I don't have any reason to mix "." and ":" in expressions other than with "." as the last ssyntax character. I think it should ideally expand right-to-left no matter what the ssyntax characters are; note that, under this scheme, "a:b:c" would expand to (compose a:b c) -> (compose (compose a b) c), which is equivalent to the current expansion (compose a b c), and the Arc Compiler could transform the former into the latter.

Arc seems to load properly, and the ssyntax works the way I like it.

  arc> factorial.3
  6
  arc> inc:factorial.3
  7
  arc> factorial:inc:factorial.3
  5040


2 points by rocketnia 4866 days ago | link

In Arc I sometimes like to say (a.b:c.d e f), which this change breaks. But I don't mind that. ^_^

Anyway, what you're talking about is already how Penknife works: Infix operators on the right are always handled first. An interesting result is that a!b ssyntax is a bit redundant under this setup. Here's an Arc demonstration:

  ; with ! ssyntax
  a.b!c.d        ->  (a.b!c d)
                 ->  ((a.b (quote c)) d)
  
  ; without ! ssyntax
  a.b:quote.c.d  ->  (a.b:quote.c d)
                 ->  ((a.b:quote c) d)
                 ->  (((compose a.b quote) c) d)
                 ->  ((a.b (quote c)) d)
So now the following ssyntaxes are all abbreviations for things that are a little more verbose but just as edit-efficient:

  a!b  -> a:quote.b
  .a   -> get.a
  !a   -> get:quote.a
  ~a   -> no:a
The ssyntaxes left over are a:b, a.b, and a&b.

In Penknife, I've been thinking about having infix operator such that a`b.c is (b a c). Arc could do this if a`b expanded to something like (opcurry b a), where 'opcurry was a metafn such that ((opcurry a b c) d e f) expanded to (a b c d e f). Then the only essential ssyntaxes would be a`b and a.b:

  a&b  -> a`andf.b
  a:b  -> a`compose.b
  a!b  -> a`compose.quote.b
  .a   -> get.a
  !a   -> get`compose.quote.a
  ~a   -> no`compose.a
Of course, at a certain point the verbosity is a bit silly. I've defined ` as a curry function in Penknife so that I can test it out a`foo.b with everyday functions foo, like 1`+.2 and so forth, and I've found it pretty cumbersome to actually type. Still, it's less cumbersome than 1.+(2), I suppose. :-p

Maybe it'll be useful in an axiomatic way. Perhaps a Penknife-like or Arc-like language can have ` and . as its only basic infix operators, with all other infix operators being abbreviations defined in terms of those two....

Hmm, an alternate axiomatic approach is to treat a`b.c as a single ternary operator a{b}c.

  a&b  -> a{andf}b
  a:b  -> a{compose}b
  a.b  -> a{call-op}b  ; where (call-op a b) expands to (a b)
  a!b  -> a{compose}quote{call-op}b
  .a   -> get{call-op}a
  !a   -> get{compose}quote{call-op}a
  ~a   -> no{compose}a
This is essentially equivalent to Penknife's approach, except that Penknife uses Haskell-style naming rules (infix identifier or alpha identifier) rather than delimiters. So it looks like the a`b.c approach is just a way to simulate this syntax system within itself. Pretty interesting. XD

-----

3 points by akkartik 4866 days ago | link

Have "a:b.c" expand to (a:b c)

Wart unconsciously got this right (compose is ^):

  wart> (wt-transform 'a^b.c)
  (call* (compose* a b) c)

-----