[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: how useful are collecting lists?

This page is part of the web mail archives of SRFI 110 from before July 7th, 2015. The new archives for SRFI 110 contain all messages, not just those from before July 7th, 2015.




On 03/13/2013 08:13 PM, David A. Wheeler wrote:
David Vanderson:
This makes the most sense to me, I'll put it in the draft revision I'm writing.
Okay!  If you could post proposed revisions as a unified diff
("diff -u"), or do it as a git branch from the readable "develop" branch,
that'd be great.

--- David A. Wheeler


First attempt attached. Please let me know if I'm going in a decent direction.

Thanks,
Dave
diff --git a/SRFI-110.html b/SRFI-110.html
index 41a93b2..55b3db9 100644
--- a/SRFI-110.html
+++ b/SRFI-110.html
@@ -3152,58 +3152,12 @@ is a single datum.
 
 <h3 id="collecting-lists">Collecting lists (&lt;* ... *&gt;)</h3>
 <p>
-Sweet-expressions without collecting lists (&lt;* ... *&gt;)
-work well in a vast number of circumstances.
-However, they can be somewhat awkward for two use cases:
+Each sweet-expression is ended with a blank line, which is usually what you
+want.  There is one circumstance where that behavior is awkward: a long
+sequence of definitions within an initial statement.
 </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 structures.</li>
-<li>A let-style statement with one or two variables
-with short initial values.</li>
-</ol>
-<p>
-Let&#8217;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 collecting 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.
-</p>
-
-<p>
-For example, here&#8217;s an example from the R7RS Scheme specification
-for define-library:
-</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)))
-        (do ((i 0 (+ i 1)))
-            ((= i n) grid)
-          (let ((v (make-vector m #f alse)))
-            (vector-set! grid i v)))))
-    (define (rows grid) (vector-length grid))
-    (define (cols grid)
-      (vector-length (vector-ref grid 0)))
-    (define (ref grid n m)
-      (and (&lt; -1 n (rows grid))
-           (&lt; -1 m (cols grid))
-           (vector-ref (vector-ref grid n) m)))
-    (define (put! grid n m v)
-      (vector-set! (vector-ref grid n) m v))))
-</pre>
 <p>
-This is easily reformatted into this sweet-expression, but
-notice the long sequence of indented definitions that, if long,
-loses a lot of horizontal space and can invite mistakes:
+An accidental blank line between two internal definitions will end the initial statement:
 </p>
 <pre>
 define-library
@@ -3218,6 +3172,8 @@ define-library
         ! let (v(make-vector(m #f alse))) vector-set!(grid i v)
     define rows(grid) vector-length(grid)
     define cols(grid) vector-length(vector-ref(grid 0))
+
+; above blank line prematurely ends define-library
     define ref(grid n m)
       and
         {-1 &lt; n &lt; rows(grid)}
@@ -3225,9 +3181,56 @@ define-library
         vector-ref vector-ref(grid n) m
     define put!(grid n m v) vector-set!(vector-ref(grid n) m v)
 </pre>
+<p>
+You can work around this for short sequences by:
+</p>
+<ol>
+<li>removing blank lines, or</li>
+<li>adding a comment on each blank line, or</li>
+<li>adding \\ on each blank line</li>
+</ol>
+<p>
+For longer sequences, use collecting lists (&lt;* ... *&gt;).  The &lt;* and
+*&gt; represent opening and closing parentheses, but restart indentation
+processing at the beginning, and collect any sweet-expressions inside.  In a
+collecting list, horizontal spaces after the initial &lt;* are consumed, and
+then sweet-expressions are read.  These t-expressions must not be indented
+(though you can indent lines with only ;-comments).
+</p>
 
 <p>
-But wholesale changes to sweet-expressions do not seem warranted
+Here an example of using collecting lists for the library structure above:
+</p>
+<pre>
+define-library
+  example grid
+  export make rows cols ref each rename(put! set!)
+  import scheme(base)
+  &lt;* begin
+
+define make(n m)
+  let (grid(make-vector(n)))
+    do (i(0 {i + 1}))
+    ! {i = n} grid
+    ! let (v(make-vector(m #f alse))) vector-set!(grid i v)
+
+define rows(grid) vector-length(grid)
+define cols(grid) vector-length(vector-ref(grid 0))
+
+define ref(grid n m)
+  and
+    {-1 &lt; n &lt; rows(grid)}
+    {-1 &lt; m &lt; cols(grid)}
+    vector-ref vector-ref(grid n) m
+
+define put!(grid n m v) vector-set!(vector-ref(grid n) m v)
+*&gt;
+</pre>
+<p>
+Why a new construct?  
+</p>
+<p>
+Wholesale changes to sweet-expressions do not seem warranted
 for this special case, because
 there are reasons that sweet-expressions are defined the way they are.
 It is fundamental that a child line is indented from its parent, since
@@ -3240,9 +3243,57 @@ Ending a definition at a blank line is very convenient for interactive use,
 and interactive and file notation should be identical
 (since people often switch between them).
 </p>
+<p>
+Note: Python works around this by having different semantics for files vs.
+interactive use.
+</p>
+<p>
+The collecting 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).
+The &#8220;*&#8221; is more arbitrary, but the collecting list markers
+need to be multiple
+characters to distinguish them from the less-than and greater-than procedures,
+and this seemed to be a fairly distinctive token that is rarely used
+in existing code.
+</p>
+<p>
+For schemes with implicit begin, collecting lists can be used after a .:
+</p>
+<pre>
+define-library . &lt;*
+
+example grid
+export make rows cols ref each rename(put! set!)
+import scheme(base)
+
+define make(n m)
+  let (grid(make-vector(n)))
+    do (i(0 {i + 1}))
+    ! {i = n} grid
+    ! let (v(make-vector(m #f alse))) vector-set!(grid i v)
+
+define rows(grid) vector-length(grid)
+define cols(grid) vector-length(vector-ref(grid 0))
+
+define ref(grid n m)
+  and
+    {-1 &lt; n &lt; rows(grid)}
+    {-1 &lt; m &lt; cols(grid)}
+    vector-ref vector-ref(grid n) m
+
+define put!(grid n m v) vector-set!(vector-ref(grid n) m v)
+*&gt;
+</pre>
 
 <p>
-Now let&#8217;s look at the second use case.
+Happily, collecting lists can also help a let-style statement with one or
+two variables with short initial values.
+</p>
+<p>
 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)
@@ -3293,52 +3344,6 @@ let (x(5) y(7))
 </pre>
 
 <p>
-A <i>collecting list</i> is surrounded by the markers &lt;* and *&gt;.
-The &lt;* and *&gt; represent opening and closing
-parentheses, but restart indentation processing
-at the beginning instead of disabling indentation processing,
-and collect any sweet-expressions inside.
-The purpose of collecting lists is to make it easy to clearly
-express these and similar use cases.
-</p>
-
-<p>
-In a collecting list, horizontal spaces after the initial &lt;*
-are consumed, and then sweet-expressions are read.
-These t-expressions must not be indented (though you can indent
-lines with only ;-comments).
-</p>
-
-<p>
-Here an example of using collecting lists for the library structure above:
-</p>
-<pre>
-define-library
-  example grid
-  export make rows cols ref each rename(put! set!)
-  import scheme(base)
-  &lt;* begin
-
-define make(n m)
-  let (grid(make-vector(n)))
-    do (i(0 {i + 1}))
-    ! {i = n} grid
-    ! let (v(make-vector(m #f alse))) vector-set!(grid i v)
-
-define rows(grid) vector-length(grid)
-define cols(grid) vector-length(vector-ref(grid 0))
-
-define ref(grid n m)
-  and
-    {-1 &lt; n &lt; rows(grid)}
-    {-1 &lt; m &lt; cols(grid)}
-    vector-ref vector-ref(grid n) m
-
-define put!(grid n m v) vector-set!(vector-ref(grid n) m v)
-*&gt;
-</pre>
-
-<p>
 Here are some examples of collecting lists for the let-variable cases:
 </p>
 <pre>
@@ -3352,19 +3357,6 @@ let &lt;* x 5 \\ y 7 *&gt;
 </pre>
 
 
-<p>
-The collecting 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).
-The &#8220;*&#8221; is more arbitrary, but the collecting list markers
-need to be multiple
-characters to distinguish them from the less-than and greater-than procedures,
-and this seemed to be a fairly distinctive token that is rarely used
-in existing code.
-</p>
 
 <h3 id="reserved">Reserved marker ($$$)</h3>
 <p>