Proposal: make $ serve as GROUP, leave \\ to always be SPLIT Beni Cherniavsky-Paskin (02 May 2013 08:46 UTC)
Re: Proposal: make $ serve as GROUP, leave \ to always be SPLIT David A. Wheeler (04 May 2013 03:13 UTC)

Re: Proposal: make $ serve as GROUP, leave \ to always be SPLIT David A. Wheeler 04 May 2013 03:13 UTC

On Thu, 2 May 2013 01:46:16 -0700, Beni Cherniavsky-Paskin <xxxxxx@users.sf.net> wrote:

> This is kinda late to say this, and I'm not at all sure it's an
> improvement.  But the thought won't leave me, so better now than never...

I'm a little skeptical, but it's important that we think this through *now* vs. later.

> \\'s dual duty is nagging me.  Intuitively, I grasp the operators like this:
> - SPLIT prevents creation of lists ("a \\ b") or at least fractures them
> ("a b \\ c d").
> - GROUP's sole reason[*] for existence is to express a list of child lines.
> - SUBLIST (usually) creates lists.

> Which leads me to feel that \\'s two meanings are opposite — SPLIT is
> "anti-list", GROUP is "pro-list".

Well... that's not really the original intent.

But let's go with that thought and see where it takes us!

> => What if we make a lone $ on a line serve as GROUP, making $ always "pro-list"?
> Then we'd write:
>
> let
> ! $
> ! ! x foo()
> ! ! y bar()
> ! do-stuff(x y ...)
>
> [this currently isn't legal (trailing $), and would produce a spurious (((x
> ...) (y ...))) level if it were legal.]

One immediately consequence is that we could not to later add semantics for "$" at the end of the line, such as the "Beni lite" semantics.  Currently a "$" at the end-of-the-line is an error, making it easy to define a later extension using it without fear of interfering with existing sweet-expressions.

That's not a disaster, but worth noting.

> I don't really think the "pro-list vs anti-list" argument is critical; the
> more important criteria are:
> * Can this unify the handling of leading $ vs head $ rest?
>   If this can reduce us from 3 central constructs to 2, it's a major win.
>   If leading $ remains a special case, just subtler, maybe it's a loss.

I don't think so.  From a quick look at the BNF (the it_expr production), it looks like it'd create a slightly more complicated BNF.

Currently leading GROUP_SPLIT and "scomments" (e.g., #|...|#) are actually handled by exactly the same branch of the same rule; there's actually no difference in how they work.  If we make *only* "$" do this, we'd have to have more branches to distinguish them, because a leading scomment like "#;(x y) z" would have to be treated differently than "$ z".  And if it's *added* to "$", while retaining leading \\ semantics, then we'd have copy several BNF lines to make leading "$" do that as well with no obvious reason to allow both.  In either case, it creates more sub-branches of the BNF.

I think it's very *doable*, but I don't think it "unifies" anything, and it eliminates certain symmetries discussed below.

> * Is this consistent with $ in haskell?  [don't know if this Q even means anything]

In Haskell, "$" *requires* a left-hand-side.  So "$" at the beginning of a line is an extension beyond Haskell.

You can blame me for that extension; my primary goal was to make it easy to write one-line lists of one element, where the element is also a list.  This happens in some common constructs like "let" and "do".  It also makes the "$" construct more regular:

a b $ c d => (a b (c d))
a $ b c d => (a (b c d))
$ a b c d => ((a b c d))

Presumably, if you start an expression with a "$" you intend for something different to happen, vs:
a b c d => (a b c d)

I *have* used it in real code, so it's not an unusable feature.

> Another issue I see with the current leading $ behavior is this
> inconsistency:
>
> foo (a b) ==> (foo (a b))
> foo $ a b ==> (foo (a b))
> (a b) ==> (a b)
> $ a b ==> ((a b))  ; huh?!

Not inconsistent.  If you view the $ operator as "add the RHS as one element to the end of LHS list", and presume that the LHS is () if it's empty, then that's the semantics you end up with.

a b ==> (a b)
$ (a b) ==> ((a b))

> foo a ==> (foo a)
> foo $ a ==> (foo a)
> a ==> a
> $ a ==> (a)  ; huh?!

Again, the "$" makes the RHS the "last element of the list on the left-hand-side... even if the left-hand-side list is empty."

> In other words, I feel that since "$ ..." always produces one object
> (whether atom or list), it should be exempt from wrapping in a list if "$
> ..." is the first thing on a line.
> This implies that "$ $ $ a" ==> a.  I'm not sure I love that, but that's
> how "\\ \\ \\ a" works now.

True, but we don't need TWO no-op operators.

> [*] I've  ignored the do-nothing leading \\ usage for stylisitically
> indenting some things, e.g. Arc's flat if and keyword args:
>
> if
> ! cond1
> ! \\ then1 ...
> func
> ! kw:
> ! \\ arg ...
>
> IIRC this is currently ascribed to GROUP's disappearing act, but the same
> effect with \\ could also be explained as a SPLIT with nothing on one side.

Absolutely.

> Alternatively, you can drop the behavior from \\ and use $ instead:
>
> if
> ! cond1
> ! $ then1 ...
> func
> ! kw:
> ! $ arg ...
>
> but that'd miss the symmetry that now exists with one-liner form:
>
> if
> ! cond1 \\ then1 ...
> func
> ! kw: \\ arg ...

Right.  There's another symmetry, also; note that these are equivalent:
foo
! a
! \\
! b
<==>
foo
! a \\ b

It even works at the top level, e.g.:
cos(0)
\\
sin(0)
<==>
cos(0) \\ sin(0)

... which is intriguing because we don't even have to store state to make it work, it just falls out from the rules.

These symmetries fall out because of the way GROUP and SPLIT are defined... moving their functions to a different operator would make the symmetries fail.

> P.S. Cosmetic points:
>
> - We'd lose the diagonal look of \\ which felt appropriate for GROUP.

Yes.  Which is why it's that character sequence.

> + The remaining sense of \\ will be familiar to TeX users ;-|
>   Curiously, the blank-line semantics (comment = not blank) also match.

--- David A. Wheeler