For Gauche 0.9.5


Next: , Previous: , Up: 基本的な構文   [Contents][Index]

4.10 定義

Special Form: define variable expression
Special Form: define (variable . formals) body …

[R7RS+] この形式はトップレベル (ローカルな束縛が無い状態) とローカルスコープがある状態とで 別の意味を持ちます。

トップレベルでは、この形式は変数variableに対するグローバルな束縛を定義します。 最初の形式では、expressionが評価され、その結果が変数variableの値となります。

(define x (+ 1 2))
x ⇒ 3
(define y (lambda (a) (* a 2)))
(y 8) ⇒ 16

2番目の形式は手続きを定義するための構文的な修飾で、以下の形式と同じです。

(define (name . args) body …)
  ≡ (define name (lambda args body …))

このフォームがローカルスコープの中に現われた場合、ローカル変数の束縛となります。 (内部define)。

内部defineはlambdaやその他のローカル束縛を作る構文の、本体部分の先頭に置けます。 これらは、下に示すようにletrec*フォームと等価です。

(lambda (a b)
  (define (cube x) (* x x x))
  (define (square x) (* x x))
  (+ (cube a) (square b)))

 ≡

(lambda (a b)
  (letrec* ([cube (lambda (x) (* x x x))]
            [square (lambda (x) (* x x))])
    (+ (cube a) (square b))))

内部defineは実質的にletrec*フォームなので、 相互再帰する内部関数を書けますし、また同じスコープで先に導入された定義を 使って定義される値を計算することもできます。しかし、 内部defineフォームの後に定義される値を使うことはできません。 そういったプログラムを書いてもGaucheは直ちにエラーを報告しませんが、 あとでおかしな結果が出ることがあります。

(lambda (a)
  (define x (* a 2))
  (define y (+ x 1))  ; yの値を計算するのにxを使ってよい
  (* a y))

(lambda (a)
  ;; odd?の中からeven?を参照するのはok。odd?が定義される時点ではeven?
  ;; の値は使われず、odd?が呼ばれた時に初めて使われるから。
  (define (odd? x) (or (= x 1) (not (even? (- x 1)))))
  (define (even? x) (or (= x 0) (not (odd? (- x 1)))))
  (odd? a))

(lambda (a)
  ;; これはダメ。yを定義する時点でxの値を使わないとならないので。
  ;; ただし、すぐにはエラーとならないかもしれない。
  (define y (+ x 1))
  (define x (* a 2))
  (* a y))

束縛を作るフォームのボディー内で、内部defineは同じレベルにあるすべての式より前に 現れなければなりません。例えば次のコードは、defineフォームの 前に式(print a)があるので不正です。

(lambda (a)
  (print a)
  (define (cube x) (* x x x))  ; error!
  (cube a))

束縛を作るフォームのボディー中に、式を置かず内部defineだけを書いておくのも不正ですが、 Gaucheは特にエラーを出しません。

beginは新しいスコープを作らないことに注意してください(順次実行参照)。 beginの中に現われるdefineは、あたかもbeginとそれを囲む 括弧が無いかのように振舞います。すなわち、以下の2つの形式は等価です。

(let ((x 0))
  (begin
    (define (foo y) (+ x y)))
  (foo 3))
 ≡
(let ((x 0))
  (define (foo y) (+ x y))
  (foo 3))
Macro: define-values (var …) expr
Macro: define-values (var var1 … . var2) expr
Macro: define-values var expr

[R7RS] まずexprが評価され、続いて各値がvarに順に束縛されます。 最初の形式では、expr

(define-values (lo hi) (min&max 3 -1 15 2))

lo ⇒ -1
hi ⇒ 15

二番目の形式では、exprvar var1 …に対応する数か それ以上の値を生成しなければなりません。余った値はリストになってvar2に 束縛されます。

(define-values (a b . c) (values 1 2 3 4))

a ⇒ 1
b ⇒ 2
c ⇒ (3 4)

最後の形式では、exprの生成する全ての値がリストにまとめられ、varに 束縛されます。

(define-values qr (quotient&remainder 23 5))

qr ⇒ (4 3)

define-valuesdefineが許されるところならどこでも使えます。 つまり、内部defineにdefine-valuesを混ぜて使えるということです。

(define (foo . args)
  (define-values (lo hi) (apply min&max args))
  (define len (length args))
  (list len lo hi))

(foo 1 4 9 3 0 7)
 ⇒ (6 0 9)

Let-valuesも参照してください。

Special Form: define-constant variable expression
Special Form: define-constant (variable . formals) body …

このフォームはトップレベルでしか使えません。 トップレベルのdefineと同じように動作しますが、 コンパイラはvariableの値が今後変更されないものとして 最適化されたコードを生成します。

variableの値をset!で変更しようとするとエラーとなります。 variableを再定義することは許されますが、警告が表示されます。

“内部define-constant” にあたるものはありません。宣言が無くても コンパイラはどのローカル束縛が変更されないかを検出して最適化できるからです。

Special Form: define-in-module module variable expression
Special Form: define-in-module module (variable . formals) body …

この形式はトップレベルでしか使えません。 variableのグローバルな束縛をmodule中に作成します。 moduleはモジュール名を表すシンボルか、モジュールオブジェクトで なければなりません。moduleがシンボルの場合、その名前を持つ モジュールが既に存在している必要があります。

expressionは現在のモジュール中で評価されます。

2番目の形式は次の形式の構文的修飾です。

(define-in-module module variable (lambda formals body …))

註: シンボルが現在のモジュール中で定義されているか(グローバルな束縛を持つか) を調べるには、global-variable-bound?が使えます (モジュールイントロスペクション参照)。


Next: , Previous: , Up: 基本的な構文   [Contents][Index]