On Jan 15, 2013 2:57 PM, "David A. Wheeler" <dwhee...@dwheeler.com> wrote:
> Sweet-expressions without restart lists (&lt;* ... *&gt;)
> work well in a vast number of circumstances.
> However, they can be somewhat awkward for two typical use cases:
> </p>
> <ol>
> <li>A long sequence of definitions contained within an initial statement.
> This situation occurs in many library definition structures such as
> Scheme R7RS <tt>define-library</tt> and in some larger data
> <li>A let-style statement with one or two variables
> with short initial values.</li>
> </ol>

Summary: I only buy the first of the use cases; I think this construct will
be rarely used and want the sematics to be as simple as possible; I propose
some alternative ideas below.

> <p>
> Let's begin with the first use case.
> When there is a long sequence of definitions contained within an
> initial statement, and no special notation like restart lists,
> all the definitions in the long sequence must be
> indented and none can be separated by a blank line
> (since that would end the entire sequence, not just a definition).
> Indenting almost an entire file is annoying, and needing no blank lines
> for that long invites mistakes.

If we separate the 2 issues, I feel the no-blank-lines is the more
problematic of them.  In Python, I'm fine with most of my defs being
indented because they're class methods, but couldn't live without new lines.
Do you agree?

> <p>
> Now let's look at the second use case.
> The sweet-expression notation cleanly handles cases where let-expression
> variables have complex values (e.g., using \\), but for simple cases
> (1-2 variables having short initial values)
> it can take up more vertical space than traditional formatting.
> Using a leading "$" takes up somewhat less vertical space, but it still
> takes up an additional line for a trivial case, it does not work
> the same way for let expressions with 2 variables,
> and David A. Wheeler thinks it is a rather unclear construction.
> You can also use parenthetical notation directly, but this is
> relatively ugly and it is annoying to need to do this for a common case.

I completely don't get it.
What's wrong about ((x 5) (y 7)) or (x{5} y{7}),
and why is <* x 5 *> or <* (x 5) *)> any better?
When compressing nested lists on one line, parens are the - clearest way to
represent structure.
Specifically, I dislike the usage where <* x y *> implies a double list by
restarting the multiple-items-on-a-"line" rule.  While I see the consistent
logic of this semantics, it's IMHO way too hard to scan this visually as a
double list - a problem ((...)) doesn't have.

As I see it, we need some solution for the very-long-form problem, while
one-liner-let is a solved problem.
If restricting <* .. *> to EOL - or even requiring them to stand alone on a
line - makes for a simpler spec, I'd much rather see that rather than fine
tuning the inline semantics.

> let  ; Using \\ takes up a lot of vertical space in simple cases
>   \\
>     x 5
>   {x + x}
> let
>   \\
>     x 5
>     y 7
>   {x + x}
> let  ; Less vertical space, but 1 variable only
>   $ x 5
>   {x + 5}
> ; Note "$ x 5 $ y 7" isn't right; that maps to ((x 5 (y 7))).

I agree that "two-liner-let" is not a solved problem.  We can either cram
it on 1 line, or nicely spread on 1+N lines using \\, but not on N lines.
IMO this goes deeper than just let but I don't think abusing <*..*> is an
improvement.  I'll try to post thoughts on this in the z language thread.

> <p>
> Here are examples of the same constructs, using restart lists:
> </p>
> <pre>
> define-library
>   example grid
>   export make rows cols ref each rename(put! set!)
>   import scheme(base)
>   begin <*
> define make(n m)
>   let (grid(make-vector(n)))
> ...
> *>
IMHO, it's very ugly that "example grid ..." are indented when the body of
the library isn't.  Indentation should be (at least) non-decreasing!

If I were to use a construct like this, I'd either have "define ..."
indented deeper (only using <*..*> for blank line freedom), or flatten the
containing lists at indent zero (on the theory it should actually be

example grid
export make rows cols ref each rename(put! set!)
import scheme(base)

define make(n m)
  let (grid(make-vector(n)))

I'm deliberately restricting <* to the head of the list.  I see it as an
esoteric construct, and this is the simplest least-surprise version.

> <p>
> The restart list symbols are carefully chosen.
> The characters &lt; and &gt; are natural character pairs that are
> available in ASCII.
> What is more, they are not delimiters, so any underlying
> Scheme reader will not immediately stop on reading them
> (making it easier to reuse).

Which is also a weakness IMHO.  Visually, < and > don't feel like a list
start/end, at least not to lisp eyes.  ([{ / }]) have a history as list
delimiters, < / > not so much.

Which leads me to the following idea: let the list be started / ended by
(...), but have a notation that *only* [re]starts t-expr processing:

  (example grid)
  (export make rows cols ref each (rename put! set!))
  (import (scheme base))

     define (make n m)
       let ((grid (make-vector n)))

     define ...

Those could even be spelled verbosely, e.g. #!sweet-expressions ...
#!end-sweet-expressions.  (I don't mind, on the theory that it's an
esoteric use case, needed only in long code.)  This has the benefit that
we'd need something like that to enable t-exprs in the first place, on
strictly backward-compatible platforms.
[BTW, the support for empty lines here is neatly implicit.  The syntax
starts a *series* of expressions; an empty line *still* terminates an expr,
but there can be more exprs.]


Another conceptual simplication I thought of is making <* .. *> actually be
the indent/dedent tokens synthesized by the "indentation preprocessor".
One less concept to explain, plus a free-form alternative to anything
achievable with indentation!

One practical issue is how they interact with existing indentation / stuff
on same line.  This has to be resolved to make it a "free-form"
alternative, but let's ignore that for now and have them on separate lines.

I don't like the resulting constructs:

define-library (example grid)
export make rows cols ref each (rename put! set!)
import (scheme base)
define (make n m)
  let ((grid (make-vector n)))

define ...

The location of <* not at start of list is bizzare!  This works with
indentation, but without the visual clue it's bad.

Also, allowing empty lines need artificial support.
E.g. "An empty line is assumed to have indentation 0, implying *> tokens
for any pending physical indent - but NOT for any unclosed <* appearing as
<* in the source.



A crazier idea: what if { ... } would NOT disable t-expr processing?!

define-library (example grid)
  export make rows cols ref each (rename put! set!)
  import (scheme base)
    define (make n m)
      let ((grid (make-vector n)))

    define ...

C-style syntax for free!?  Issues:

- works well only with 1-item lists, like begin here; I don't see any way
to do define-library{ without opening a ().
- too sensitive to spaces - begin { would mean a different thing.
- the ship may have sailed with the SRFI.  While it didn't cover n-exprs,
the same "must disable it for backward compatibility with SRFI 105 " logic
may now apply.

Master Java SE, Java EE, Eclipse, Spring, Hibernate, JavaScript, jQuery
and much more. Keep your Java skills current with LearnJavaNow -
200+ hours of step-by-step video tutorials by Java experts.
SALE $49.99 this month only -- learn more at:
Readable-discuss mailing list

Reply via email to