[ < ] [ > ]   [ << ] [ Up ] [ >> ]         [Top] [Contents] [Index] [ ? ]

4.6 変数束縛

Special Form: let ((var expr) …) body …
Special Form: let* ((var expr) …) body …
Special Form: letrec ((var expr) …) body …

[R5RS] 各変数varexprの値に束縛されているローカルな環境を作成し、 その中でbody …を評価します。varはシンボルでなければ ならず、重複があってはなりません。body …の最後の式の値が このフォームの値となります。

これらの3つのフォームの違いは、exprが評価される時点のスコープにあります。 letexprletフォームに入る前の環境において評価します。 let*exprを順に、それ以前のvarが束縛された環境において評価して ゆきます。letrecは全てのvarが仮想的に不定の値に束縛された環境において 各exprを評価します。letrecは相互再帰的なローカル関数を定義する場合に 必要です。

 
(define x 'top-x)

(let  ((x 3) (y x)) (cons x y)) ⇒ (3 . top-x)
(let* ((x 3) (y x)) (cons x y)) ⇒ (3 . 3)

(let ((cons (lambda (a b) (+ a b)))
      (list (lambda (a b) (cons a (cons b 0)))))
  (list 1 2))  ⇒ (1 2 . 0)

(letrec ((cons (lambda (a b) (+ a b)))
         (list (lambda (a b) (cons a (cons b 0)))))
  (list 1 2))  ⇒ 3
Macro: let1 var expr body …

変数が一つしか無い場合の便利なマクロです。次のように展開されます。

 
(let ((var expr)) body …)
Macro: if-let1 var expr then
Macro: if-let1 var expr then else

このマクロは次のようなイディオムを簡素化します。

 
(let1 var expr
  (if var then else))
Macro: rlet1 var expr body …

このマクロは次のようなイディオムを簡素化します。

 
(let1 var expr
  bodyvar)
Macro: and-let* (binding …) body …

[SRFI-2] 簡単に言うと、このフォームはlet*のように動作しますが、 bindings中の式が#fに評価されたらそこで評価を打ち切り #fを返します。

bindingは以下のいずれかの形式でなければなりません。

(variable expression)

expressionが評価されます。それが真の値を返したら、その値がvariable に束縛され、次のbindingへと進みます。もうbindingが無ければ body …が評価されます。もしexpression#fを返したら、 評価を打ち切り、and-let*から#fを返します。

(expression)

この形式ではvariableが省略されています。Expressionが評価され、 その結果は評価を続行するか打ち切るかを判断するためにのみ使われます。

bound-variable

この形式ではbound-variableは束縛変数を示す識別子でなければなりません。 その変数の値が偽でなければ評価を続行します。

いくつか例を挙げます。次のコードは連想リストalistからkeyを 探し、見つかったらその値を返します。

 
(and-let* ((entry (assoc key alist))) (cdr entry))

もしargが正確な整数の文字列表現だった場合はnumを返し、そうでなければ 0を返します:

 
(or (and-let* ((num (string->number arg))
               ( (exact? num) )
               ( (integer? num) ))
      num)
    0)

以下のコードはとあるサーバーのポート番号をいくつかの可能性 (環境変数、設定ファイル…)の中から探す仮想的なコードです。

 
(or (and-let* ((val (sys-getenv "SERVER_PORT")))
      (string->number val))
    (and-let* ((portfile (expand-path "~/.server_port"))
               ( (file-exists? portfile) )
               (val (call-with-input-string portfile port->string)))
      (string->number val))
    8080) ; default
Macro: fluid-let ((var val) …) body …

動的スコープの変数をエミュレートするマクロです。 varfluid-letフォームを含むスコープで定義されている 変数でなければなりません。valは式です。 fluid-letはまずvalを評価し、 valvarに動的スコープで束縛してbody … を評価します。

マルチスレッド環境下では、varの値の変化は全てのスレッドから見えます。 このフォームは主として他の処理系のコードを移植する際の利便性のために 追加されました。スレッドローカルな動的状態を実現するには、 パラメータオブジェクト(gauche.parameter - パラメータ参照)を 使って下さい。

 
(define x 0)

(define (print-x) (print x))

(fluid-let ((x 1))
  (print-x))  ⇒ ;; prints 1
Special Form: receive formals expression body …

[SRFI-8] この構文により、多値を受け取ることができます。 formalsはシンボルのリストです。不完全なリストであっても構いません。 expressionが評価され、返された値がlambda形式の引数の束縛と 同じようにしてformals内の変数と束縛され、その環境下でbody …が 評価されます。

 
(define (divrem n m)
  (values (quotient n m) (remainder n m)))

(receive (q r) (divrem 13 4) (list q r))
  ⇒ (3 1)

(receive all (divrem 13 4) all)
  ⇒ (3 1)

(receive (q . rest) (divrem 13 4) (list q rest))
  ⇒ (3 (1))

なお、多値call-with-valuesreceiveと等価な手続き的インタフェースです。 多値を複数のトップレベル変数に束縛するには、define-values (定義参照) が使えます。 また、SRFI-11 (srfi-11 - Let-values) のlet-valueslet*-valuesletのような形式で多値を扱うことができます。

Macro: rec var expr
Macro: rec (name . vars) expr …

[SRFI-31] 再帰的な参照のある式の評価を行うマクロです。

最初の形式は、varexprの結果に束縛される状態でexprを 評価します。 2番目の形式は以下の形式と等価です。

 
(rec name (lambda vars expr …))

例:

 
;; constant infinite stream
(rec s (cons 1 (delay s)))

;; factorial function
(rec (f n) 
  (if (zero? n)
      1 
      (* n (f (- n 1)))))

[ < ] [ > ]   [ << ] [ Up ] [ >> ]

This document was generated by Shiro Kawai on November, 22 2009 using texi2html 1.78.