From 0723bb3cdf5508cc2b0a9ab7ef8ff418b748d6cb Mon Sep 17 00:00:00 2001 From: Justin Ethier Date: Fri, 9 Dec 2016 23:48:19 -0500 Subject: [PATCH] Fixup docs --- docs/api/srfi/2.md | 53 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 51 insertions(+), 2 deletions(-) diff --git a/docs/api/srfi/2.md b/docs/api/srfi/2.md index 3df2ae76..adbeaf71 100644 --- a/docs/api/srfi/2.md +++ b/docs/api/srfi/2.md @@ -2,15 +2,64 @@ The `(srfi 2)` library provides the `and-let*` macro, an `and` with local bindings. +# Overview + Like an ordinary `and`, an `and-let*` special form evaluates its arguments -- expressions -- one after another in order, till the first one that yields `#f`. Unlike `and`, however, a non-#f result of one expression can be bound to a fresh variable and used in the subsequent expressions. `and-let*` is a cross-breed between `let*` and `and`. See the [SRFI document](http://srfi.schemers.org/srfi-2/srfi-2.html) for more information. +# Rationale + +In case of an ordinary and formed of proper boolean expressions: + + (and E1 E2 ...) + +expression E2, if it gets to be evaluated, knows that E1 has returned non-#f. Moreover, E2 knows exactly what the result of E1 was -- #t -- which E2 can use to its advantage. If E1 however is an extended boolean expression, E2 can no longer tell which particular non-#f value E1 has returned. Chances are it took a lot of work to evaluate E1, and the produced result (a number, a vector, a string, etc) may be of value to E2. Alas, the `and` form merely checks that the result is not an #f, and throws it away. If E2 needs it, it has to compute that value anew. This proposed `and-let*` special form lets constituent expressions get hold of the results of already evaluated expressions, without re-doing their work. + +`and-let*` can be thought of as a combination of `let*` and `and`, or a generalization of `cond`'s send operator `=>`. An `and-let*` form can also be considered a sequence of guarded expressions. In a regular program, forms may produce results, bind them to variables and let other forms use these results. `and-let*` differs in that it checks to make sure that every produced result "makes sense" (that is, not an `#f`). The first "failure" triggers the guard and aborts the rest of the sequence (which presumably would not make any sense to execute anyway). Examples: + + (and-let* ((my-list (compute-list)) ((not (null? my-list)))) + (do-something my-list)) + + (define (look-up key alist) + (and-let* ((x (assq key alist))) (cdr x))) + + (or + (and-let* ((c (read-char)) + ((not (eof-object? c)))) + (string-set! some-str i c) + (set! i (+ 1 i))) + (begin (do-process-eof))) + + ; A more realistic example + ; Parse the 'timestamp' ::= 'token1' 'token2' + ; token1 ::= 'YY' 'MM' 'J' + ; token2 ::= 'GG' 'gg' "/" + (define (parse-full-timestamp token1 token2) + (and-let* (((= 5 (string-length token1))) + ((= 5 (string-length token2))) + (timestamp + (OS:string->time "%m/%d/%y %H:%M" + (string + (string-ref token1 2) (string-ref token1 3) #\/ + (string-ref token1 0) (string-ref token1 1) #\/ + (case (string-ref token1 4) + ((#\8 #\9) #\9) (else #\0)) + (string-ref token1 4) #\space + (string-ref token2 0) (string-ref token2 1) #\: + (string-ref token2 2) (string-ref token2 3)))) + ((positive? timestamp))) + timestamp)) + +`and-let*` is also similar to an "anaphoric AND" LISP macro [Rob Warnock, comp.lang.scheme, 26 Feb 1998 09:06:43 GMT, Message-ID: 6d3bb3$3804h@fido.asd.sgi.com]. `and-let*` allows however more than one intermediate result, each of which continues to be bound through the rest of the form. + - [`and-let*`](#and-let) # and-let* - (and-let* (claws) body +*Syntax* + + (and-let* (claws) body) claws ::= '() | (cons claw claws) claw ::= (variable expression) | (expression) | @@ -18,7 +67,7 @@ See the [SRFI document](http://srfi.schemers.org/srfi-2/srfi-2.html) for more in - The `claws` are evaluated in the strict left-to-right order - For each `claw`, the `expression` part is evaluated first (or `bound-variable` is looked up) -- If the result is #f, `and-let*` immediately returns #f +- If the result is `#f`, `and-let*` immediately returns `#f` - Otherwise, if the `claw` is of the form `(variable expression)` the `expression`'s value is bound to a freshly made `variable` - The `variable` is available for the rest of the `claws` , and the `body` - As usual, all `variable`s must be unique (like in `let*`)