R6RS:翻訳:R6RS:11.4.6 Binding constructs

R6RS:翻訳:R6RS:11.4.6 Binding constructs

11.4.6 束縛構文

本節で説明する束縛構文は限られた領域だけで可視な変数の局所束縛を作成する。 let、 let*、 letrec、 letrec* の構文はまったく同じであるが、これらは変数の束縛を確立する領域(R6RS:翻訳:R6RS:5.2 Variables, keywords, and regions 参照)が異なり、束縛に対する値が計算される順序が異なる。 let 式ではどの変数も束縛されないうちに初期値が計算される。 let* 式では束縛と評価が逐次的に行なわれる。 letrec と letrec* ではその初期値が計算されている間、すべての束縛が有効である。したがって、相互再帰的な定義ができるのである。 letrec 式えは初期値は変数に代入される前に計算される。一方、 letrec* では評価と代入が逐次的に行なわれる。

加えて、 let-values、 let*-values 束縛構文では let と let* を一般化し、複数の値に評価される式の結果を複数の変数に束縛できるようにしている。これらは let と let* と、領域を確立する方法はほぼ同じである。 let-values 式では、変数が束縛される前に初期値が計算される。 let*-values 式では、束縛が逐次的に行なわれる。

本節の束縛構文をより単純なフォームで定義した例は R6RS:翻訳:R6RS:B Sample definitions for derived forms にある。

[syntax] (let <bindings> <body>)

構文: <bindings> は次の形式をしていなければならない。

((<variable1> <init1>) ...)

各 <init> は式で <body> は R6RS:翻訳:R6RS:11.3 Bodies で説明したものである。変数はいずれも 2 回以上 <variable> に現れてはならない。

意味論: <init> が現在の環境で(何らかの規定されていない順序で)評価され、 <variable> がその結果を保持する新たな場所に束縛され、 <body> が拡張された環境で評価され、 <body> の最後の値が返る。 <variable> の各束縛は <body. をその領域とする。

(let ((x 2) (y 3))
  (* x y))                              ⇒  6

(let ((x 2) (y 3))
  (let ((x 7)
        (z (+ x y)))
    (* z x)))                           ⇒  35

R6RS:翻訳:R6RS:11.16 Iteration の名前つき let も参照。

[syntax] (let* <bindings> <body>)

構文: <bindings> は次の形式をしていなければならない。

((<variable1> <init1>) ...)

各 <init> は式で <body> は R6RS:翻訳:R6RS:11.3 Bodies で説明したものである。

意味論: let* フォームは let とほぼ同じであるが、左から右へ逐次的に <init> が評価され束縛が作成され、各束縛はその束縛の領域は <body> と同様にその右側の束縛も包含する。したがって、 2 番目の <init> は最初の束縛が可視であり、初期化された環境で評価される。後も同様である。

(let ((x 2) (y 3))
  (let* ((x 7)
         (z (+ x y)))
    (* z x)))                     ⇒  70

: let 式で束縛される変数に重複があってはならない一方、 let* で束縛される変数には重複があってもかまわない。

[syntax] (letrec <bindings> <body>)

構文: <bindings> は次の形式をしていなければならない。

((<variable1> <init1>) ...)

各 <init> は式で <body> は R6RS:翻訳:R6RS:11.3 Bodies で説明したものである。変数はいずれも 2 回以上 <variable> に現れてはならない。

意味論: <variable> が新たな場所に束縛され、 <init> がその結果の環境で(規定されていない何らかの順序で)評価され、各 <variable> に対応する <init> の評価結果が代入され、 <body> が結果の環境で評価され、 <body> の最後の式の値が返る。 <variable> の各束縛は letrec 式全体を領域とし、これにより相互再帰的な手続きを定義することが可能になっている。

(letrec ((even?
          (lambda (n)
            (if (zero? n)
                #t
                (odd? (- n 1)))))
         (odd?
          (lambda (n)
            (if (zero? n)
                #f
                (even? (- n 1))))))
  (even? 88))   
                        ⇒  #t

各 <init> はいずれの <variable> も代入ないし参照することなしに評価できなければならない。最も一般的な letrec の利用法では、 <init> はすべて lambda 式で、この制約は自動的に満足される。別の制約として、各 <init> の継続は一度だけしか起動すべきではない。

実装系の義務: 実装系は <init> 式の評価中の <variable> への参照を検知しなければならない(ひとつの特定の評価順序と <init> 式の評価順序を使って)。実装系がこの制約への違反を検知した場合には &assertion コンディション型の例外を発生させなければならない。実装系は各 <init> の継続が 2 回以上起動されたかどうかを検知しなくてもよい。だがそれでも、これを検知した場合には &assertion コンディション型の例外を発生させなければならない。

[syntax] (letrec* <bindings> <body>)

構文: <bindings> は次の形式をしていなければならない。

((<variable1> <init1>) ...)

各 <init> は式で <body> は R6RS:翻訳:R6RS:11.3 Bodies で説明したものである。変数はいずれも 2 回以上 <variable> に現れてはならない。

意味論: <variable> が新たな場所に束縛され、左から右の順序で対応する各 <variable> に <init> が代入され、その結果の環境で <body> が評価され、 <body> の最後の式の返した値が返される。左から右への評価・代入順序を除けば、 <variable> の各束縛は letrec* 式全体をその領域とし、相互再帰的な関数を定義することが可能になっている。

(letrec* ((p
           (lambda (x)
             (+ 1 (q (- x 1)))))
          (q
           (lambda (y)
             (if (zero? y)
                 0
                 (+ 1 (p (- y 1))))))
          (x (p 5))
          (y x))
  y)
                        ⇒  5

各 <init> は対応する <variable> や <bindings> 内で後続する <variable> を代入ないし参照することなしに評価できなければならない。別の制約として、各 <init> の継続は 2 回以上起動されるべきではない。

実装系の義務: 実装系は、 <init> の評価中に対応する <variable> や <bindings> 中で後続する <variable> のいずれかの値を参照していることを検知しなければならない。実装系がこのような制約への違反を検知した場合、 &assertion コンディション型の例外を発生させなければならない。実装系は <init> の継続が 2 回以上起動されたことを検知してもしなくてもよい。だが、検知した場合には、 &assertion コンディション型の例外を発生させなければならない。

[syntax] (let-values <mv-bindings> <body>)

構文: <bindings> は次の形式をしていなければならない。

((<formals1> <init1>) ...)

各 <init> は式で <body> は R6RS:翻訳:R6RS:11.3 Bodies で説明したものである。どの変数も 2 回以上 <formals> の集合中に現れてはならない。

意味論: <init> が現在の環境で(規定されていない何らかの順序で)評価され、 <formals> 中の変数が <init> の返した値を格納した新たな場所に束縛される。ここで、 <formals> は戻り値に対して lambda 式中の <formals> がその引き数と照合されるのと同じ方法で照合される。その後、拡張された環境で <body> が評価され、 <body> の最後の式の返した値が返される。変数の各束縛は <body> をその領域とする。 <formals> が一致しない場合には、 &assertion コンディション型の例外が発生する。

(let-values (((a b) (values 1 2))
             ((c d) (values 3 4)))
  (list a b c d))         ⇒ (1 2 3 4)

(let-values (((a b . c) (values 1 2 3 4)))
  (list a b c))                    ⇒ (1 2 (3 4))

(let ((a ’a) (b ’b) (x ’x) (y ’y))
  (let-values (((a b) (values x y))
               ((x y) (values a b)))
    (list a b x y)))               ⇒ (x y a b)

[syntax] (let*-values <mv-bindings> <body>)

構文: <Mv-bindings> は次の形式をしていなければならない。

((<formals1> <init1>) ...)

各 <init> は式で <formals> は R6RS:翻訳:R6RS:11.3 Bodies で説明したものである。各 <formals> 中で、どの変数も 2 回以上現れてはならない。 ((<formals1> <init1>) ...),

意味論: let*-values は let-values と類似であるが、 <init> は左から右に逐次的に評価・束縛の作成がされ、束縛を含む各 <formals> の束縛は <body> と同様にその右側もその領域とする。したがって、 2 番目の <init> は最初の <formals> の束縛が可視で初期化された状態の環境で評価される。後続のものも同様である。

(let ((a ’a) (b ’b) (x ’x) (y ’y))
  (let*-values (((a b) (values x y))
                ((x y) (values a b)))
    (list a b x y)))          ⇒ (x y x y)

: let-values 式で束縛される変数はすべて重複があってはならないが、一方 let*-values では異なる <formals> で束縛される変数には重複があってもかまわない。


Last modified : 2009/09/20 01:00:18 UTC