From 2f062c6f2df9ec62c1527bb17005ce529351bbc9 Mon Sep 17 00:00:00 2001
From: Kaz Kylheku <kaz@kylheku.com>
Date: Fri, 22 Mar 2019 06:27:52 -0700
Subject: doc: update let/let* doc.

* txr.1: specification of let and let* is substantially
revised for clarity, and behavior of duplicate symbols,
and special variables.
---
 txr.1 | 131 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 117 insertions(+), 14 deletions(-)

diff --git a/txr.1 b/txr.1
index 4f87a33f..e758a790 100644
--- a/txr.1
+++ b/txr.1
@@ -13346,18 +13346,37 @@ evaluate forms in that scope. The operator symbol, either
 .code let
 or
 .codn let* ,
-is followed by a list which can contain any mixture of variable
-name symbols, or
+is followed by a list which can contain any mixture of
+.meta sym
+or
 .cblk
 .meti >> ( sym << init-form )
 .cble
-pairs.  A symbol
-denotes the name of variable to be instantiated and initialized
-to the value
-.codn nil .
-A symbol specified with an init-form denotes
-a variable which is initialized from the value of the
+pairs.
+Each
+.meta sym
+must be a symbol, and specifies the name of variable to be instantiated and
+initialized.
+
+The
+.cblk
+.meti >> ( sym << init-form )
+.cble
+variant specifies that the new variable
+.meta sym
+receives an initial value from the
+evaluation of
 .metn init-form .
+The plain
+.meta sym
+variant specifies a variable which is initialized to
+.codn nil .
+The
+.metn init-form -s
+are evaluated in order, by both
+.code let
+and
+.codn let* .
 
 The symbols
 .code t
@@ -13374,19 +13393,20 @@ is that in
 .codn let* ,
 later
 .codn init-form -s
-have visibility over the variables established by earlier variables
-in the same let* construct. In plain
+are in scope of the variables established by earlier variables in the same
+.code let*
+construct. In plain
 .codn let ,
-the variables are not visible to any of the
-.metn init-form -s.
+the
+.metn init-form -s
+are evaluated in a scope which does not include any of the variables.
 
-When the variables are established, then the
+When the variables are established, the
 .metn body-form -s
 are evaluated in order. The value of the last
 .meta body-form
 becomes the return value of the
 .codn let .
-
 If there are no
 .metn body-form -s,
 then the return value
@@ -13395,6 +13415,89 @@ is produced.
 
 The list of variables may be empty.
 
+The list of variables may contain duplicate
+.metn sym -s
+if the operator is
+.codn let* .
+In that situation, a given
+.meta init-form
+has in scope the rightmost duplicate of any given
+.meta sym
+that has been previously established.
+The
+.metn body-form -s
+have in scope the rightmost duplicate of any
+.meta sym
+in the construct.
+Therefore, the following form calculates the value 3:
+
+.cblk
+  (let* ((a 1)
+         (a (succ a))
+         (a (succ a)))
+    a)
+.cble
+
+Each duplicate is a separately instantiated binding, and may be independently
+captured by a lexical closure placed in a subsequent
+.codn init-form :
+
+.cblk
+  (let* ((a 0)
+         (f1 (lambda () (inc a)))
+         (a 0)
+         (f2 (lambda () (inc a))))
+    (list [f1] [f1] [f1] [f2] [f2] [f2]))
+
+  --> (1 2 3 1 2 3)
+.cble
+
+The preceding example shows that there are two mutable variables named
+.code a
+in independent scopes, each respectively captured by the separate closures
+.code f1
+and
+.codn f2 .
+Three calls to
+.code f1
+increment the first
+.code a
+while the second
+.code a
+retains its initial value.
+
+Under
+.codn let ,
+the behavior of duplicate variables is unspecified.
+
+Implementation note: the \*(TX compiler diagnoses and rejects duplicate
+symbols in
+.code let
+whereas the interpreter ignores the situation.
+
+When the names of a special variables is specified in
+.code let
+or
+.code let*
+remain, a new binding is created for them in the dynamic environment, rather
+than the lexical environment.
+In
+.codn let* ,
+later
+.metn init-form -s
+are evaluated in a dynamic scope in which previous dynamic variables
+are established, and later dynamic variables are not yet established.
+A special variable may appear multiple times in a
+.codn let* ,
+just like a lexical variable. Each duplicate occurrence extends the
+dynamic environment with a new dynamic binding.
+All these dynamic environments are removed when the
+.code let
+or
+.code let*
+form terminates. Dynamic environments aren't captured by lexical
+closures, but are captured in delimited continuations.
+
 .TP* Examples:
 .cblk
   (let ((a 1) (b 2)) (list a b)) -> (1 2)
-- 
cgit v1.2.3