Updated the documentation, added pointer to hosted version
This commit is contained in:
		
							parent
							
								
									66e435aa92
								
							
						
					
					
						commit
						5a92ba298d
					
				
					 3 changed files with 88 additions and 138 deletions
				
			
		|  | @ -550,54 +550,53 @@ | |||
|   <section title="Loop expansion"> | ||||
|     The main chunk of a loop expands into something like the following: | ||||
|     A goof loop expands into something looking like this: | ||||
|     <verbatim> | ||||
|       (let* (<outer-binding> ... | ||||
|              final-function (lambda (<final-binding>) <final-expr>)) | ||||
|         (let goof-loop ((<accumulator> <accumulator-init>) ... (<loop-var> <loop-var-init>) ...) | ||||
|           (if (or <check> ...) | ||||
|     <example> | ||||
|       (let* (OUTER-BINDING ... | ||||
|              final-function (lambda (FINAL-BINDING) FINAL-EXPR)) | ||||
|         (let goof-loop ((ACCUMULATOR ACCUMULATOR-INIT) ... (LOOP-VAR LOOP-VAR-INIT) ...) | ||||
|           (if (or CHECK...) | ||||
|             (begin | ||||
|               <for-clause-finalizer> ... | ||||
|               (final-function (<accumulator-finalizer> <accumulator>) ...)) | ||||
|             (let ((<body-binding> ... <body-binding-expr>) ...) | ||||
|               (let ((<user-binding> ... <user-binding-expr>) ...) | ||||
|                 (match-let ((<parenthesised-pattern> <match-expr>)) | ||||
|                   (if (and <when-expr> ...)             | ||||
|               FOR-CLAUSE-FINALIZER ... | ||||
|               (final-function (ACCUMULATOR-FINALIZER ACCUMULATOR) ...)) | ||||
|             (let ((BODY-BINDING ... BODY-BINDING-EXPR) ...) | ||||
|               (let ((USER-BINDING ...USER-BINDING-EXPR) ...) | ||||
|                 (match-let ((PARENTHESISED-PATTERN MATCH-EXPR)) | ||||
|                   (if (and WHEN-EXPR ...) | ||||
|                       (cond | ||||
|                         ((or <user-break> ...) | ||||
|                           <for-clause-finalizer> ... | ||||
|                           (final-function (<accumulator-finalizer> <accumulator>) ...)) | ||||
|                         ((or USER-BREAK ...) | ||||
|                           FOR-CLAUSE-FINALIZER ... | ||||
|                           (final-function (ACCUMULATOR-FINALIZER ACCUMULATOR) ...)) | ||||
|                         (else | ||||
|                           <loop-body> | ||||
|                           (goof-loop <accumulate> ... <loop-var-next> ...)) | ||||
|                       (goof-loop <accumulator> ... <loop-var-next> ...))))))))) | ||||
|      | ||||
|       <outer-binding>: are provided by accumulators or for clauses for bindings that are not passed as an argument to the loop, for example a vector. The vector is bound here, and the index into the vector is the thing iterated over. | ||||
|                           LOOP-BODY | ||||
|                           (goof-loop ACCUMULATE ... LOOP-VAR-NEXT ...)) | ||||
|                       (goof-loop ACCUMULATOR ... LOOP-VAR-NEXT ...))))))))) | ||||
|     </example> | ||||
|     OUTER-BINDING: are provided by accumulators or for clauses for bindings that are not passed as an argument to the loop, for example a vector. The vector is bound here, and the index into the vector is the thing iterated over. | ||||
| 
 | ||||
|       <final-binding> and <final-expr>: When the iteration ends, this function is called with the results of the :acc clauses. In the case of (:acc lst-acc (listing ...)), the name of the accumulator is never lst-acc in the loop body, but only in the <final-expr>. In case of (listing ...) the accumulated results are reversed before the final function. | ||||
|      FINAL-BINDING and FINAL-EXPR: When the iteration ends, this function is called with the results of the :acc clauses. In the case of (:acc lst-acc (listing ...)), the name of the accumulator is never lst-acc in the loop body, but only in the FINAL-EXPR. In case of (listing ...) the accumulated results are reversed before the final function. | ||||
| 
 | ||||
|       <accumulator> and  <loop-variable>: <accumulator> holds the current state of an accumulator clause. This is not necessarily the same binding as the user provided as the name, as described above. <loop-var> is the current state of a :for clause.  | ||||
|      ACCUMULATOR and  LOOP-VAR: ACCUMULATOR holds the current state of an accumulator clause. This is not necessarily the same binding as the user provided as the name, as described above. LOOP-VAR is the current state of a :for clause. | ||||
| 
 | ||||
|       <check>: Checks for :for-clauses. In the case of (in-list ...) this would check for (not (pair? ...)). | ||||
|      CHECK: Checks for :for-clauses. In the case of (in-list ...) this would check for (not (pair? ...)). | ||||
| 
 | ||||
|       <for-clause-finalizer>: some :for clauses need to be finalized. In the case of (in-file ...) the open file handle is closed at any point where the iteration stops. | ||||
|      FOR-CLAUSE-FINALIZER: some :for clauses need to be finalized. In the case of (in-file ...) the open file handle is closed at any point where the iteration stops. | ||||
| 
 | ||||
|       <accumulator-finalizer>: <accumulator-finalizer> is any preprocessing done to <accumulator> before passing it on to the final-function. In the case of (listing ...) that would be (reverse ...). | ||||
|      ACCUMULATOR-FINALIZER: ACCUMULATOR-FINALIZER is any preprocessing done to ACCUMULATOR before passing it on to the final-function. In the case of (listing ...) that would be (reverse ...). | ||||
| 
 | ||||
|       <body-binding> and <body-binding-expr>:<body-binding> are the names the user provided for the body bindings. In the case of (:for a (in-list '(1 2 3))) the body binding would be (a (car name-of-loop-variable)). The body binding may be an (ice-9 match) pattern. More on that below. | ||||
|      BODY-BINDING and BODY-BINDING-EXPR: BODY-BINDING are the names the user provided for the body bindings. In the case of (:for a (in-list '(1 2 3))) the body binding would be (a (car name-of-loop-variable)). The body binding may be an (ice-9 match) pattern. More on that below. | ||||
| 
 | ||||
|       <parenthesised-pattern> and <match-expr>: If a <user-binding> is not an identifier, it is presumed to be a match-let pattern. The result is bound to a variable and matched against this match-let. | ||||
|      PARENTHESISED-PATTERN and MATCH-EXPR: If a USER-BINDING is not an identifier, it is presumed to be a match-let pattern. The result is bound to a variable and matched against this match-let. | ||||
| 
 | ||||
|       <when-expr>: the user supplied :when or :unless guard expression. | ||||
|      WHEN-EXPR: the user supplied :when or :unless guard expression. | ||||
|            | ||||
|       <user-break>: user-supplied :break guard. | ||||
|      USER-BREAK: user-supplied :break guard. | ||||
| 
 | ||||
|       <loop-body>, <accumulate>, and <loop-var-next>: The user supplied body of the loop. If the loop is not named (i.e: in loops where the user controls the iteration) an expression for the next loop iteration is added to the body. <accumulate> is the expression the accumulator clause provided to accumulate a new value. For (:acc acc (listing elem)) that is (cons elem acc). <loop-var-next> is the expression evaluated to get the next iteration's loop variable. In the case of (in-list lst) that is (cdr lst). If a loop name is provided there is no implicit next loop.  | ||||
|      LOOP-BODY, ACCUMULATE, and LOOP-VAR-NEXT: The user supplied body of the loop. If the loop is not named (i.e: in loops where the user controls the iteration) an expression for the next loop iteration is added to the body. ACCUMULATE is the expression the accumulator clause provided to accumulate a new value. For (:acc acc (listing elem)) that is (cons elem acc). LOOP-VAR-NEXT is the expression evaluated to get the next iteration's loop variable. In the case of (in-list lst) that is (cdr lst). If a loop name is provided there is no implicit next loop. | ||||
|      | ||||
|       <accumulator-init> and <loop-var-init>: <accumulator-init> are ALL accumulator init values, including the ones in subloops. For (listing ...) that is the empty list. <loop-var-init> is the initial loop vars. | ||||
|      ACCUMULATOR-INIT and LOOP-VAR-INIT: ACCUMULATOR-INIT are ALL accumulator init values, including the ones in subloops. For (listing ...) that is the empty list. LOOP-VAR-INIT is the initial loop vars. | ||||
| 
 | ||||
| 
 | ||||
|       In case of subloops, those are placed instead of <loop-body>. They use the same final-function, and instead of quitting when any <check> triggers they go out to the outer loop. | ||||
|     </verbatim> | ||||
|      In case of subloops, those are placed instead of LOOP-BODY. They use the same final-function, and instead of quitting when any CHECK triggers they go out to the outer loop. | ||||
|   </section> | ||||
|   <section title="Porting"> | ||||
|     The bulk of goof-loop is written in portable syntax-rules. That code can be found in `goof-impl.scm` and all files under the `goof` directory. The major non-portable part is the macro that is bound in every loop to the user-given name of the loop. In the guile implementation this is implemented in syntax-case, and should be portable to any r6rs scheme. The guile implementation does a non-hygienic comparison of the variables in the named update, so to not have to deal with unwanted shadowing: | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Linus
						Linus