通常の AND と同じく、 AND-LET* 特殊フォームはその引数 (式) を順番に評価し、 評価値が #f になると評価を中断する。 しかし AND と違って、#f ではない評価値は新しい変数に束縛され、 その変数は後続の式で使用することができる。 つまり、AND-LET* は LET* と AND の合いの子である。
次のように、ブール値 (#f または #t) に対して通常の AND を適用する場合、
(AND E1 E2 ...)
式 E2 を評価するときには E1 が真値を返したことを知っている。
さらに言えば、E1 は #t を返したことを知っているので、
E2 を評価するときに、この知識に基づいて何らかの効率化を行える。
しかし、E1 が拡張されたブール式である (#f, #t 以外の値を返す) 場合、
E2 は E1 がどのような真値を返したかを知ることができない。
それを知るためには、E2 は E1 と同じ計算を行って、
その結果 (数値、ベクタ、文字列など) を得るしかない。
残念なことに、AND は評価値が #f であるかどうかだけを調べたら、
その値を捨ててしまうのである。
E2 がその値を知りたければ、再計算するしかない。
このような欠点を補うため、式の評価値を保持することで再計算を行わないで済むような
AND-LET* 特殊フォームを提案する。
AND-LET* は、LET* と AND を組み合わせたものとして捉えることができるし、 COND の => 演算子の一般化として捉えることもできる。 AND-LET* は、条件付き式のシーケンスだと捉えることもできる。 通常のプログラムでは、フォームは値を生成し、 それを変数に束縛して、別のフォームがそれを使えるようにする。 AND-LET* では、フォームが生成した値が #f ではないことを検査するという点で異なる。 ある式が #f に評価されると、 残りの式の評価は中断される (ある式が #f に評価されると、残りの式を評価する意味がないと判断される)。 以下に使用例を示す。
(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* は、LISP の前方照応的 AND (anaphoric AND) マクロ [Rob Warnock, comp.lang.scheme, 26 Feb 1998 09:06:43 GMT, Message-ID: 6d3bb3$3804h@fido.asd.sgi.com] とも類似している。 しかし、AND-LET* は複数の中間値を扱うことができ、 その中間値を変数に束縛して、残りのフォームで使用することができる。
AND-LET* (CLAWS) BODY CLAWS ::= '() | (cons CLAW CLAWS) CLAW ::= (VARIABLE EXPRESSION) | (EXPRESSION) | BOUND-VARIABLE
eval[ (AND-LET* (CLAW1 ...) BODY), env] = eval_claw[ CLAW1, env ] andalso eval[ (AND-LET* ( ...) BODY), ext_claw_env[CLAW1, env]] eval[ (AND-LET* (CLAW) ), env] = eval_claw[ CLAW, env ] eval[ (AND-LET* () FORM1 ...), env] = eval[ (BEGIN FORM1 ...), env ] eval[ (AND-LET* () ), env] = #t eval_claw[ BOUND-VARIABLE, env ] = eval[ BOUND-VARIABLE, env ] eval_claw[ (EXPRESSION), env ] = eval[ EXPRESSION, env ] eval_claw[ (VARIABLE EXPRESSION), env ] = eval[ EXPRESSION, env ] ext_claw_env[ BOUND-VARIABLE, env ] = env ext_claw_env[ (EXPRESSION), env ] = env-after-eval[ EXPRESSION, env ] ext_claw_env[ (VARIABLE EXPRESSION), env ] = extend-env[ env-after-eval[ EXPRESSION, env ], VARIABLE boundto eval[ EXPRESSION, env ]]
完全な実装と検証コードが ここ から入手できる (これは http://pobox.com/~oleg/ftp/Scheme/vland.scm のコピーである)。
この AND-LET* の実装は、(Gambit 用の) 低レベル マクロを使用しており、 AND-LET* を AND と LET のツリーに書き換える。 検証コードは、仕様どおりに動作することを検証するだけでなく、 AND-LET* が構文エラーを検出することも検証している。
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
最終更新日時: Sun Jan 28 13:40:28 MET 2007