R6RS:翻訳:Standard Libraries:5 Control structures

R6RS:翻訳:Standard Libraries:5 Control structures

5 章 制御構造

本章では (rnrs control (6)) ライブラリについて述べる。本ライブラリは有用な制御構造を提供する。

[syntax] (when <test> <expression1> <expression2> ...)

[syntax] (unless <test> <expression1> <expression2> ...)

構文: <test> は式でなければならない。

意味論: when 式は <test> 式をを評価することにより評価される。 <test> が真の値に評価っされた場合残りの <expression> が順に評価され、最後の <expression> の結果が when 式全体の結果として返される。 unless 式は <test> 式を評価することにより評価される。 <test> が #f に評価された場合残りの <expression> が順に評価され、最後の <expression> の結果が when 式全体の結果として返される。それ以外の場合は unless 式は未規定値を返す。

when や unless が末尾文脈にあった場合、最後の <expression> も末尾文脈にある。

(when (> 3 2) ’greater)         ⇒ greater
(when (< 3 2) ’greater)         ⇒ unspecified
(unless (> 3 2) ’less)         ⇒ unspecified
(unless (< 3 2) ’less)         ⇒ less

when 式と unless 式は派生式形であり、下のマクロを使って定義することができる。

(define-syntax when
  (syntax-rules ()
    ((when test result1 result2 ...)
     (if test
         (begin result1 result2 ...)))))

(define-syntax unless
  (syntax-rules ()
    ((unless test result1 result2 ...)
     (if (not test)
         (begin result1 result2 ...)))))

[syntax] (do ((<variable1> <init1> <step1>) ...) (<test> <expression> ...) <command> ...)

構文: <init>、 <step>、 <test>、<command> は式でなければならない。 <variable> は互いに相違する変数でなければならない。 Syntax: The <init>s, <step>s, <test>s, and <command>s must be expressions. The <variable>s must be pairwise distinct variables.

意味論: do 式は繰り返し構文である。束縛される変数を指定し、それが最初にどのように束縛されるか指定し、各繰り返しでどのように更新されるかを指定する。

do 式は次のように評価される。 <init> が(何らかの未規定の順序で)評価され、 <variable> が新たな場所に束縛され、 <init> 式の結果が <variable> の束縛に格納され、繰り返し段階が始まる。

繰り返しではまず <test> を評価する。評価結果が #f であったら <command> が順に評価され、 <step> 式が何らかの未規定の順序で評価され、 <variable> がその結果を保持する新たな場所に束縛されて、次の繰り返しが始まる。

<test> が真値に評価された場合には <expression> が左から右に評価され、最後の <expression> の値が返る。 <expression> が存在しない場合には、 do 式は未規定値を返す。

<variable> の束縛の有効範囲は do 式の <init> 部分以外全体である。

<step> は省略することもでき、その場合には (<variable> <init>) の代わりに (<variable> <init> <variable>) と書いたように動作する。

do 式が末尾文脈に現れた場合には <exression> ... はR6RS:翻訳:R6RS:11.20 Tail calls and tail contextsで言う <tail sequence> である。すなわち、最後の <expression> も末尾文脈である。

(do ((vec (make-vector 5))
     (i 0 (+ i 1)))
    ((= i 5) vec)
  (vector-set! vec i i))                  ⇒  #(0 1 2 3 4)

(let ((x ’(1 3 5 7 9)))
  (do ((x x (cdr x))
       (sum 0 (+ sum (car x))))
      ((null? x) sum)))                     ⇒  25

次の do の定義は変数節を展開するのに小技を使っている。

(define-syntax do
  (syntax-rules ()
    ((do ((var init step ...) ...)
         (test expr ...)
         command ...)
     (letrec
       ((loop
         (lambda (var ...)
           (if test
               (begin
                 #f ; avoid empty begin
                 expr ...)
               (begin
                 command
                 ...
                 (loop (do "step" var step ...)
                       ...))))))
       (loop init ...)))
    ((do "step" x)
     x)
    ((do "step" x y)
     y)))

[syntax] (case-lambda <case-lambda clause> ...)

構文: 各 <case-lambda clause> は (<formals> <body>) の形式をしていなければならない。 (<formals> <body>)

<formals> は lambda フォームと同様で(R6RS:翻訳:R6RS:1.6 Procedures)、 <body> は R6RS:翻訳:R6RS:11.3 Bodies の節に述べられている通りである。

'意味論: case-lambda 式は手続きに評価される。この手続きが適用されると、引き数を順番に <case-lambda clause> と照合しようとする。以下の条件が満たされると引き数は <case-lambda clause> と一致する。

引き数に一致した最初の節について、 <formals> の変数が lambda と同じ方法で引き数値を格納した新たな場所に束縛される。

case-lambda 式の <body> の最後の式は末尾文脈である。

引き数がどの節とも一致しなかった場合には &assertion コンディション型の例外が発生する。

(define foo
  (case-lambda 
   (() ’zero)
   ((x) (list ’one x))
   ((x y) (list ’two x y))
   ((a b c d . e) (list ’four a b c d e))
   (rest (list ’rest rest))))

(foo)         ⇒ zero
(foo 1)         ⇒ (one 1)
(foo 1 2)         ⇒ (two 1 2)
(foo 1 2 3)         ⇒ (rest (1 2 3))
(foo 1 2 3 4)         ⇒ (four 1 2 3 4 ())

case-lambda キーワードは lambda を使って次のマクロで定義することができる。

(define-syntax case-lambda
  (syntax-rules ()
    ((_ (fmls b1 b2 ...))
     (lambda fmls b1 b2 ...))
    ((_ (fmls b1 b2 ...) ...)
     (lambda args
       (let ((n (length args)))
         (case-lambda-help args n
           (fmls b1 b2 ...) ...))))))

(define-syntax case-lambda-help
  (syntax-rules ()
    ((_ args n)
     (assertion-violation #f
       "unexpected number of arguments"))
    ((_ args n ((x ...) b1 b2 ...) more ...)
     (if (= n (length ’(x ...)))
         (apply (lambda (x ...) b1 b2 ...) args)
         (case-lambda-help args n more ...)))
    ((_ args n ((x1 x2 ... . r) b1 b2 ...) more ...)
     (if (>= n (length ’(x1 x2 ...)))
         (apply (lambda (x1 x2 ... . r) b1 b2 ...)
                   args)
         (case-lambda-help args n more ...)))
    ((_ args n (r b1 b2 ...) more ...)
     (apply (lambda r b1 b2 ...) args))))

Last modified : 2008/03/17 02:21:20 UTC