2012年5月8日火曜日

Scheme第17歩


モジュールの話。
今更言うまでもなくモジュール化はコードの再利用に有効だが、Gaucheにもその機能は備わっている。…と言うか、実は全ての定義は何かしらのモジュールに属していて、基本的には同じモジュールに属するもの同士が互いに見える。今までグローバルな定義として扱ってきた
(define var 10)
等は、厳密にはuserという名前のモジュールに属する。

モジュールの定義は
(define-module モジュール名 モジュール本体...)
とする。
定義したからには当然使いたいところだが、モジュール使い方は大きく分けて2種類ある。1つはカレントモジュールの変更。もう1つは外部モジュールの参照。

カレントモジュールを変更する。すなわち、使いたいモジュールの中に入ってしまえば、これまで居たモジュールの内部が見えなくなる代わりに、新たに入るモジュールの内部が見えるようになる。
(select-module モジュール名)
とすると、それ以降(からファイル終端まで)のフォームは指定したモジュール内で評価される。また、
(with-module モジュール名 フォーム...)
とすると、カレントモジュールを一時的に変更して、指定したフォームを評価する。

カレントモジュールを変更することなく参照できる外部モジュールを参照する方法の1つにimportがある。
(define-module foo
  (export visible1 visible2)
  (define visible1 100)
  (define visible2 200)
  (define invisible 300)
)
(import foo)
(print visible1 visible2)
(print invisible) ; エラー
このようにモジュールをimportすると、exportされているシンボルのみがカレントモジュールから見えるようになる。importにオプションを与えれば、細かい見え方の制御も可能。
なお、モジュールの定義を同名のファイルに記述しておけば
(require “foo”)
(import foo)
とする代わりに、useマクロを利用して
(use foo)
と簡潔に記述できる。

exportを使うと、外部モジュールをより密接にカレントモジュールに取り込む。
(define-module bar
  (export exported)
  (define exported 1000)
  (define not-exported 2000)
)
(define-module baz
  (extend bar)
  (export disp)
  (define disp (lambda () (print exported not-exported)))
)
(import baz)
(print exported)
(disp)
(print not-exported) ; エラー
例えば上記の例では、barをextendしたbazの中では、barのexportedとnot-exportedの両方が見える。またbazもexportedをexportしたことになる。しかし、not-exportedはexportされていないので、bazをimportしただけのカレントモジュールからは見えない。
exportするモジュールは複数指定可能。また、exportはuseと同様、指定したモジュールのファイルがまだロードされていなかったらロードする。

0 件のコメント:

コメントを投稿