Arc Forumnew | comments | leaders | submitlogin
Optional outer parentheses / exterior symbols
10 points by tokipin 6127 days ago | 17 comments

  Optional Outer Parentheses (An acronym of ill omen?)
For example:

  = a 5
  
  def foo (x) (+ x 1)
I removed all the outer parens from the News code. The paste is available here: http://codepad.org/Yv8VjZuD for lack of a place to upload things.

It looks pretty nice in my opinion. The main implementation issue I see is that to support multiline forms, a single newline would need to keep the expression in the same form, while multiple newlines would seperate forms:

  = a 1        ->        (= a 1
    b 2                     b 2)
  
  = a 1
               ->        (= a 1)
  b 2                    (b 2)
I think it looks nice in source code, but it would be very convenient in the REPL where 1-liners are common. I already feel urges to leave out outer parens while in the REPL.

  Exterior Symbols
Examples of the sorts of things I mean by "exterior symbols":

  4 * (pr "hi")        ->        (repeat 4 (pr "hi"))

  (fn () (pr "hi")) :     ->   ((fn () (pr "hi")))

  (fn (a) (pr a)) : 'hi   ->   ((fn (a) (pr a)) 'hi)

  pr : 'h 'i              ->  (pr 'h 'i)

  'h 'i : pr              ->  (pr 'h 'i)

  'h 'i : (fn (a b)       ->  ((fn (a b)
              (pr a b))            (pr a b)) 'h 'i)
Excluding the last couple examples, the ":" could have the same nature as the current composition operator except that non-functional arguments would be considered functions which return those arguments.

"Piping":

  (fn (x d e) (pr (+ x d e))) <= (fn (foo) (* foo 2)) 2 bar => (fn (x d e) (pr (- x d e)))
Which would become:

  (fn (z1 z2)
      (with (a ((fn (foo) (* foo 2)) z1)
            b 2
            c z2)
            ((fn (x d e) (pr (+ x d e))) a b c)
            ((fn (x d e) (pr (- x d e))) a b c)))
Usage of "|" as "with":

  (pr a b) | a 'h b 'i       ->       (with (a 'h b 'i)
                                            (pr a b))

  a 'h b 'i | (pr a b)       ->       (with (a 'h b 'i)
                                            (pr a b))
All these exterior symbolisms are intended to be nestable (just put parentheses around them.) An example I found nice which uses both optional outer parens and exterior symbols:

  pr a b | a 'h b 'i        ->        (with (a 'h b 'i)
                                              (pr a b))
Other possibilities are scope/environment switches and stuff like that. Or something. I'm just giving rough, haphazard, and questionable examples of possibilities. I'm probably glazing over some fundamental issue somewhere in the basis, but as heuristics these topics aren't bad. Sometimes interesting things can happen when considering formalisms in their own light, a la the coincidentally-named exterior forms of math.


3 points by eds 6127 days ago | link

I like the look of optional outer parens. It should be fairly easy to implement without too much complication with indentation.

I'm a little dubious about external symbols, though; they just don't look very Lispy to me. If these are to be integrated into the official Arc, I think we need to be sure of their worth. (The : function application operator, for example, doesn't look like it saves hardly any typing.) But if we got readmacro support in Arc, perhaps some or all of these could be implemented by users, inside Arc.

I don't particularly like the (4 * ...) because it interferes with implicit infix math (although others may not care about that as much as I do).

Piping just looks confusing to me; perhaps you could give an example of use?

The | as with looks like it could shorten code a bit, as it shortens the identifier name and removes one set of parens. But on the other hand, let could just be renamed to w/, and let could be made to not use an implicit do, in which case multiple variable assignments could be allowed. As an example of use:

  (w/ a 'h b 'i
    (pr a b))
I think this achieves the conciseness of the | form, and I don't think the transposition of places is very important in and of itself.

Correct me if I am wrong on any of this.

-----

3 points by tokipin 6127 days ago | link

the nice thing about using multiple newlines as markers for new forms is we don't have to worry about indentation

those examples i gave for exterior symbols are just to show the sorts of things that could be possible. the 4 * notation for example would be completely out of place in Arc. (it's a notation that one of my LOGO languages uses.) the only example of those that i think is nifty is the | notation

though that piping could have some interesting uses. basically it lets you write functional statements in directed form rather than nested

  (def a (x) (+ x 1))
  (def b (x) (* x 2))
  
  ((a => b) 3)       ->       ((fn (x) (* (+ x 1) 2)) 3)

  3 => + <= 2   ->   5 or [+ 5 _]

  a b => + => [* _ 3] => [/ 1 _] => sqrt    ->   (fn (a b)
                                                     (sqrt (/ 1 (* (+ a b) 3))))
with the "implied underscore" form of [...]:

  a b => + => [* 3] => [/ 1] => sqrt

  sqrt <= [/ 1] <= [* 3] <= + <= a b
args within nodes:

  a => [* 3] b => +      ->     (fn (a b)
                                    (+ (* a 3) b))
so it's basically composition with some things to make it more general

i wonder what tomfoolery could be done by using the list as the format for the directed graph

anyways, i don't really know what i'm talking about wrt piping, and i don't find the notation very handsome. though it just occured to me that we can already just make a 'pipe' macro/function that would allow us to write things close enough to that notation. programmable programming language indubitably

and again, these are just heuristics for the most part. maybe with the small spark of these examples, other people can come up with some useful notations, or more useful sparks that may eventually lead to some :)

-----

3 points by eds 6127 days ago | link

Oh, I didn't see your note about multiple newlines separating forms. That is an interesting approach, and removes the need for meaningful whitespace. But I have to wonder if it might get a little tiresome at the repl, since you would always have to add an extra newline to all your one line forms (unless you reverted to outer parens again).

And I now see what piping does, although I agree with you that the notation doesn't look very nice.

Perhaps external symbols could be used to do infix math? Although that might make it difficult to distinguish from when you want to do (for example):

  (map + '(1 2 3) '(4 5 6))

-----

2 points by tokipin 6127 days ago | link

yea for the REPL i'm not exactly sure. i think it would have to be limited to 1-liners. for multiple lines then you'd have to use outer parens. where it would get wack is, say, copy & pasting code into the REPL, and if that code isn't using outer parens, how would it be parsed? it wouldn't be a problem if it was pasted and read in a 'chunk', but i think in my console it's pasted line-by-line or parsed line-by-line as if manually input. i'm not sure. hmmm. we might have to say "use outer parens if you're going to paste the code into the REPL"

however, that's the behavior as it is now in the scheme REPL. a custom Arc REPL would be able to handle things like pastes appropriately (maybe. i'm not familiar with console mechanics, but even if it wasn't 'purely' possible, a timer could be used so that if the delta between the last and currently entered lines is less than X, then it would be safe to assume the sequence was pasted)

for infix math it might be best to have a marker that says "the following form is infix"

  #( (3 + 2) / 8 )     ->     (/ (+ 3 2) 8 )
some other thoughts are notations for pattern matching/RE's

  @([aA][rR][cC])

-----

5 points by eds 6127 days ago | link

I'm really uncomfortable about making the repl and file readers differ, especially to the point of being incompatible.

About a custom console, I am not sure there is any reliable way to detect when a user has pasted code into the console. (That sort of thing is probably very OS dependent.)

Even if you did set up a timer like you propose, what would it do if the user recalled some lines from a multiline entry in history? I think most consoles would only pull up one line of history at a time, so the user would have to go through each line and enter it individually. And the timing would be such as to be indistinguishable from direct input from the user.

As for infix math, if you created an infix marker like

  #( (3 + 2) / 8 )
then you really aren't saving anything over

  (# (3 + 2) / 8)
at which point you could just use a macro.

-----

1 point by tokipin 6127 days ago | link

yea that's true. i'm new to lisp so a lot of these things don't occur to me right away (well, that's my excuse at least)

-----

2 points by Jesin 6111 days ago | link

What happens if you want to interpolate @([aA][rR][cC]) into a quasiquote?

  (foo ,@([aA][rR][cC]) ,baz)
See the problem?

-----

0 points by Jesin 6111 days ago | link

What happens if you want to interpolate @([aA][rR][cC]) into a quasiquote?

  (foo ,@([aA][rR][cC]) ,baz)
See the problem?

-----

2 points by KirinDave 6127 days ago | link

Could I borrow the Python part of your brain for a moment? Much as the trees around Isengard, I suspect it requires burning.

There is a reason people fear and reject whitespace sensitivity. And it's not purely prejudice.

-----

7 points by Jesin 6127 days ago | link

In the case of Python, yes, it is prejudice. Have you ever coded in Python? If anything throws you off, it's going to be thinking in Python idioms, not the whitespace. In earlier languages, "significant indentation" meant something entirely different (columns 0-20 are comments, etc.). Python's use of indentation means that the interpreter uses the same code-block delimiters that the people reading and writing the code use.

Significant indentation is great. Wait, come back! Don't put this in the language yet! I'm not done! Significant indentation is great for languages like Python, in which code blocks are different from expressions and never go smack in the middle of a function call.

I've seen attempts to do significant indentation in Lisp, and instead of getting simple and pretty like Python, it gets all tangled and ugly. Ideas that are great in one context may be horrible in another. Need I remind you what happened when Larry Wall tried to combine all the great ideas from a bunch of different languages into one?

-----

1 point by KirinDave 6127 days ago | link

If you claim it's great for languages like python, and that's fine if you want it. I do know python, but I don't use it actively because I detest its engineer engineering and its significant whitespace.

But Lisps and Arc are not Python, or even a language like Python. And making a terminator or separator character that is both invisible and munged differently on many platforms seems like an extremely bad idea to me.

-----

2 points by geira 6119 days ago | link

> In the case of Python, yes, it is prejudice.

No, it's common sense. Call me old-fashioned, but I prefer being able to tell if code is syntactically correct just by looking at it instead of having to perform a hex dump. Never mind being able to reconstruct indentation from syntax when it eventually gets mangled in email/forum postings/code restructuring.

> Have you ever coded in Python?

Yes I have. Apart from the above caveat it's quite a nice language, although I find Ruby more elegant.

> Need I remind you what happened when Larry Wall tried to combine all the great ideas from a bunch of different languages into one?

Yes, it got hugely popular. You got a problem with that?

-----

2 points by eds 6119 days ago | link

>> In the case of Python, yes, it is prejudice.

> No, it's common sense. Call me old-fashioned, but I prefer being able to tell if code is syntactically correct just by looking at it instead of having to perform a hex dump.

Are you trying to say that source code (either with or without meaningful indentation) requires a hex dump to read? Or are you talking about object code (in which case I am pretty sure indentations is entirely irrelevant).

>> Need I remind you what happened when Larry Wall tried to combine all the great ideas from a bunch of different languages into one?

> Yes, it got hugely popular. You got a problem with that?

I don't know about you but Perl's conglomerate syntax, combined with all that extra magic, makes Perl pretty unmanageable in my opinion after a couple hundred lines of code.

From pg's essay Arc at 3 Weeks:

"We're also going to try not to make the language look like a cartoon character swearing. [...] (Dan Giffin recently observed that if you measure Perl programs by the number of keys you have to press, they don't seem so short.)"

-----

2 points by tokipin 6127 days ago | link

hehe sure you can borrow that part. i don't know any python so you'd be burning the null brain. the indentation sensitivity is actually the reason i never got interested in that language. it's probably just the fact that things aren't explicitly closed -- something i wouldn't mind in lisp but feels like standing on a plank in the middle of the ocean in a structured language like python, probably due to the mixture of symbolic and visual notation which totally weirds me out man

though i'm sure it's really just an exaggeration in my mind due to only hearing about that aspect of the language, and i probably would have gotten used to it easily enough

-----

1 point by treef 6127 days ago | link

yes it is!

-----

4 points by eds 6127 days ago | link

Please, lets not get into a "yes it is"/"no it isn't" argument here!

I am aware of some rather horrid languages that forced the use of meaningful indentation, but that doesn't make indentation evil in and of itself.

As for in Lisp, a number of people have tried to add it to Arc (including pg) without too much success. It seems that meaningful indentation lends itself much better to statement based languages than expression based ones.

-----

1 point by stefano 6127 days ago | link

To implement implicit parenthesis is possible to add a parameter to macro definitions to tell the reader how many parameters the function takes, so that it can add an opening brace when it sees a macro name and it closes it after n arguments. I've done so in a toy lisp interpreter I'm writing, but after a while i removed that feature because i didn't like implicit parehthesis, when manipulating forms within macros you have to remember about implicit parenthesis and this makes macros less natural.

-----