• Schemeファイルのロード: | ||
• ダイナミックライブラリのロード: | ||
• requireとprovide: | ||
• Autoload: | ||
• ライブラリの操作: |
[R7RS+ load]
fileをロードします。すなわち、fileに書かれたScheme式を順次読み込んで
評価します。fileの拡張子 (“.scm
”) は省略できます。
fileが “/”, “./” または “../” で始まっていない場合は、
システムファイルサーチパス (変数*load-path*
に格納されています)
の中から該当ファイルが探されます。あるいは、キーワード引数pathsにディレクトリ名の
リストを渡すことによりサーチパスを指定することもできます。
ロードに成功した場合は、実際にロードされたファイルのパス名が文字列で返されます。
指定ファイルがみつからない場合はエラーとなりますが、もしキーワード引数
error-if-not-found
に#f
が与えられていれば単にload
から
#f
が返されます。
デフォルトでは、load
はコーディング認識ポート(コーディング認識ポート参照)を
使ってソースファイルを読み込むので、ファイル先頭の"coding:
" コメントによる
文字エンコーディング指定が有効になります。
(codingコメントについてはマルチバイトスクリプトを参照)。
但し、キーワード引数ignore-codingに真の値が渡された場合、
load
はcoding-aware portを作成せず、直接ファイルポートから
ソースを読み込みます。
キーワード引数environmentにモジュールが渡された場合は、
あたかもそのモジュールがファイルの先頭でselectされたかのように
load
されます。
カレントモジュールは保存されます。つまり、file中でselect-module
によって
カレントモジュールを変更しても、load
が終わったらload
を読んだ時点の
モジュールに戻ります。
Gaucheのload
はR5RSのload
の上位互換ですが、
R7RSのload
は省略可能引数が異なります。scheme.load
- R7RS load参照。
ライブラリファイルをロードする場合は、‘use
’ (モジュールの定義と選択参照) を
使うか、下に説明する‘require
’ を使う方が良いでしょう。
load
とrequire
の違いについてはコンパイルを参照してください。
load
とrequire
がファイルを探すディレクトリのリストを保持しています。
もしサーチパスにディレクトリを追加したい場合は、この変数を直接変更せずに、下に説明する
add-load-path
を用いて下さい。
パスpathをライブラリロードパスのリストに加えます。
ロードパスはコンパイル時に確定している必要があるので、
pathはリテラル文字列でなければなりません。
pathが相対パスの場合、:relative
フラグが与えられて
いなければ、プロセスの現在のワーキングディレクトリからの相対と解釈されます。
pathは存在する必要はありません。ロードパスに存在しないディレクトリが含まれていても
単に無視されるだけです。ただ、pathが存在する場合、add-load-path
は
アーキテクチャ依存パスも探します。後で詳しく説明します。
以下の値がflag引数として認識されます。
:after
pathを現在のロードパスリストの末尾に加えます。 デフォルトでは、pathはロードパスリストの先頭に加えられます。
#t
:after
と同じです。互換性のために認識されます。
:relative
pathを、(カレントワーキングディレクトリではなく) 現在ロード中のファイルのあるディレクトリからの相対パスとして 解釈します。現在ロード中のファイルが不明な場合 (REPLから 評価されたり、ソケットから読まれたりしている場合) は、このフラグは無視されます。
ロードパスを変更したい場合、*load-path*
を直接替えずにこのフォームを
使って下さい。このフォームはコンパイル時に解釈されるのに対し、*load-path*
を
書き換えるコードは実行時に解釈されます。“use
” や “require
” は
コンパイル時のロードパスを使うので、*load-path*
への変更は反映されないかもしれません。
更に、add-load-path
はpathの下にアーキテクチャ依存のディレクトリが
ないかどうかを探し、あればそれを内部の共有ライブラリサーチパスに追加します。
例えばあなたが自分のSchemeモジュールを/home/yours/lib
に入れていて、
それが共有ライブラリを必要としていたとします。手続きgauche-architecture
(環境の問い合わせ参照)が返す値をARCHとして、
共有ライブラリを/home/yours/lib/ARCH/
に置いておくと、
共有ライブラリはそこからロードされます。この方法を取ると、複数のプラットフォーム用に
別々にコンパイルされた共有ライブラリを管理することができます。
入力ポートportから、EOFを読むまで繰り返しScheme式を読み込み評価します。
portにコーディング認識ポートを渡さない限り、"coding:
"コメント
による文字コード変換は行われないことに注意して下さい。
これらの手続きによって、現在のロードのコンテクストを知ることができます。 ロードされているファイルの中でこれらの手続きを呼ぶと、次のような値が返されます。
current-load-port
現在のフォームがロードされている入力ポート。
current-load-path
現在のフォームがロードされているファイル。
ロードのソースがファイルでない場合、この値は#f
。
current-load-history
入力ポートと行番号のペアのリストで、ロードのネスティングを示したもの。
例えばあなたがfoo.scmをロードし、そのファイルの7行目で
bar.scmがロードされ、そのファイルの18行目でbaz.scmが
ロードされたとします。current-load-history
をbaz.scm中で
呼ぶと、それは次のような値を返します。
((#<port "foo.scm"> . 7) (#<port "bar.scm"> . 18))
current-load-next
現在のファイルがロードされた時点での、ファイルサーチパスの残りを返します。
例えば *load-path*
が
("." "../lib" "/home/gauche/lib" "/share/gauche/lib")
で、
あなたがfoo.scmをロードしたところ、それが../lib/中に見つかったと
しましょう。このとき、foo.scm中でcurrent-load-next
を呼べば
("/home/gauche/lib" "/share/gauche/lib")
が返されます。
load
されていない状態で呼ばれた時は、これらの手続きはそれぞれ#f
、
#f
、()
、()
を返します。
ダイナミックローダブルライブラリ(共有ライブラリ)fileをロードしてリンクします。
fileにはサフィックス(“.so” 等) を含めないで下さい。システムによって
サフィックスは異なるため、dynamic-load
がそれを追加します。
キーワード引数init-functionは共有ライブラリ中の初期化関数の名前を 指定します。デフォルトでは、サフィックスを除くファイル名が “foo” の場合、 初期化関数名は “Scm_Init_foo” となります。
通常、共有ライブラリはSchemeモジュール中でロードされるので、モジュールユーザが 直接この手続きを呼ぶ必要はほとんどないでしょう。
一度ロードされた共有ライブラリをアンロードすることはできません。
require
とprovide
は、Lispでライブラリファイルを一度だけ
読み込むことを保証するための伝統的な方法です。
あるfeatureを最初にrequire
すると、その機能を提供する
ライブラリファイルがロードされ、その機能が提供されたということが記憶されます。
2回め以降のそのfeatureのリクエストではファイルはロードされません。
Gaucheではuse
構文 (モジュールの使用参照) が
requireのメカニズムをボンネットの下に隠してくれるので、
これらの式を直接目にする必要はほとんどありません。
もしあなたがちょっと変わった方式でライブラリを構成したくて、したがって
Gaucheの標準的なメカニズムをバイパスしたい場合に限り、使うようにしてください。
featureがまだロードされていなければロードします。featureは文字列で
なければなりません。それがそのまま(サフィックスを除く)ファイル名としてロードパスから
探されます。require
の解釈はコンパイル時に行われます。
SLIBモジュールをロードすると、require
が拡張されます。詳しくはslib
- SLIBインタフェースを
参照して下さい。
もしロードされたファイルがprovide
フォームを含んでいなかった場合、
あたかもファイルの最後に(provide feature)
があったかのように、
featureが自動的にprovideされます。これを
autoprovide機能と呼んでいます。
require
は、ファイルをロードする前に現在のモジュールを
gauche.require-base
という変更不可なモジュールにセットします。
require
されるファイルは通常、最初にdefine-module
/select-module
かdefine-library
フォームを持つので、このgauche.require-base
モジュール
を目にすることはほとんど無いでしょう。
ただ、もしロードされたファイルがモジュールを指定すること無くトップレベルの
変数を定義したり他のモジュールをimport
(use
)しようとした場合、
次のようなエラーとなります。
*** ERROR: Attempted to create a binding (a) in a sealed module: #<module gauche.require-base>
理由: require
されているファイルがどのタイミングで読まれるかを
正確にコントロールするのは難しいです(他のモジュールが既にrequireしているかも
しれないので)。もし呼び出し側の現在のモジュールをそのまま使った場合、二つの
問題が生じ得ます。(1)呼び出し側の現在のモジュールから、
define-module
やdefine-library
が見えているとは限りません。
(2)モジュールを指定しないトップレベル定義が呼び出し側の現在のモジュールに
定義を追加することは保証されません(既に別のモジュールへと読みこまれているかもしれません)。
モジュールを指定しないトップレベル定義やimportを持つファイルをrequireすることは、
単に悪いアイディアです。したがってそういう事例はエラーとすることにしました。
featureをシステムのprovideされたフィーチャーリストに加えます。
以降、featureがrequire
されてもファイルはふたたびロードされません。
require
が要求された機能を自動的にprovide
されたかのように
扱うAutoprovide機能があるために、provide
を明示的に呼ぶ必要は
ほとんど無いでしょう。provideを使いたいシチュエーションとしては
次のようなものが考えられます。
例えばfeature Xがfeature Yを置き換えるものだとします。
XはYのAPIを全て提供しますが、実装は異なります。この場合、
X.scmが一度ロードされたら、Y.scmをロードしてほしくないと思うでしょう。
X.scmに (provide "X")
と (provide "Y")
の両方を
書いておくことで、X.scmがfeature Yもprovideすると明示すれば、それが実現できます。
(注:provide
が呼ばれると、require
のautoprovide機能は
抑制されるため、X.scm中で(provide "X")
も指定する必要があります。)
もちろんの方法では、ユーザが (require "Y")
を (require "X")
より先に書いてしまったらY.scmはロードされてしまいます。
この方法は、現場において、永久的な解決が高コストになるような場合のとりあえずの
回避処置と考えるべきでしょう。
provide
しない。
feature引数に#f
を渡すことで、何のfeatureもprovide
することなく
require
によるautoprovidingを抑制できます。
これもまた、何らかの一時的な解決と考えるべきです。たとえば開発中に、
X.scmを頻繁に変更するために(require "X")
が常に
そのファイルをロードするようにさせたい、といった場合が考えられます。
X.scmのリリースの前に (provide #f)
を消しておくことを
忘れないように。また、インタラクティブにリロードしたいならば
gauche.reload
(gauche.reload
- モジュールの再ロード参照) を使うことを
おすすめします。
featureが既にprovideされていれば#t
を返します。
item … がオートロードされるように設定します。すなわち、 次にitemが参照された時、それが実際に評価される前にfile/moduleがロード されるようにします。これによって、必要とされる時までfile/moduleのロードを遅らせる ことができます。
引数file/moduleには、文字列かシンボルを指定できます。文字列の場合は
そのファイルがロードされます。シンボルの場合、その名のモジュールが(use
と
同じルールで)ロードされ、itemがfile/moduleから
オートロードを呼び出したモジュールへとインポートされます。
(モジュールのuse
の詳細についてはモジュールの定義と選択を参照して下さい)。
itemは変数名(シンボル)か、(:macro symbol)
というフォーム
でなければなりません。変数名の場合は、その変数が評価されようとした時に
指定のファイル/モジュールがロードされます。後者のフォームの場合は、
(symbol arg …)
というフォームがコンパイルされようとした
時に指定のファイル/モジュールがロードされます。後者はマクロのオートロードになります。
symbolはfile/moduleの中で定義されなければなりません。 そうでなければロード時にエラーが報告されます。
手続きのオートロードの例を示します。
(autoload "foo" foo0 foo1) (autoload "bar" bar0 bar1) (define (foobar x) (if (list? x) (map bar0 x) (foo0))) (foobar '(1 2)) ; この時点で "bar" がロードされる (foobar #f) ; この時点で "foo" がロードされる
マクロのオートロードを設定した場合、指定のファイルまたはモジュールは、 そのマクロを使っているフォームが実行されるされないにかかわらず、 コンパイラがそのフォームを見た時点でロードされることに注意してください。
ある特定のライブラリおよび/あるいはモジュールがシステムにインストールされ ているかどうかをチェックするための手続きがいくつかあります。
以下の説明の中では、patternはシンボルまたは文字列です。シンボル
である場合にはモジュール名(たとえば、foo.bar
)を指定します。
文字列である場合にはライブラリの部分パス(たとえば、"foo/bar"
)を
指定します。これはライブラリサーチパス以下で検索されます。
patternにはglob
のメタ文字と同じ意味で *
と ?
を
使うこともできます。
ライブラリ/モジュールファイルに対する基本イテレータ。この手続きは
pattern にマッチする Scheme のプログラムファイルを検索します。
検索は paths (デフォルトは標準のファイルロードパス、
*load-path*
)にリストされたディレクトリ以下でおこなわれます。
マッチしたファイル毎に、proc が、そのマッチしたモジュール名あるいは
ライブラリ名、そのプログラムファイルのフルパス、状態値、の3つの引数を
ともなって呼びだされます。seedは、初期状態値として使われ、
proc が返す値は次の proc の呼出し時に状態値として使われます。
最後の proc から返された値は library-fold
の値として返ります。
pattern がシンボルでかつ、キーワード引数 strict? が
#t
(デフォルト値)であれば、この手続きは
あたえられたモジュール名のパターンにマッチするようにみえるファイル名に
たいして library-has-module?
を適用して、
本当にそのモジュールを実装しているファイルを見付けます。
大量のモジュールにマッチさせようとすると、時間がかる可能性があります。
#f
を strict? に渡すことで、余分なチェックを回避できます。
pattern が文字列だった場合、照合はファイル名に対してのみ行われ、
strict?は無視されます。
デフォルトでは、path 中の pattern にマッチする同じ名前をもつ
2つ以上のファイルがあるばあい、path に最初に出現したものだけが
採用されます。そのライブラリに対して、require
あるいは
use
を用いたをつかった場合に得られるのはこのファイルです。
すべてのマッチしたファイルについて反復したければ、allow-duplicates?
キーワード引数に #t
を渡します。
(library-fold 'srfi.1 acons '())
⇒ ((srfi.1 . "../lib/srfi/1.scm"))
(library-fold "srfi.1" acons '())
⇒ (("srfi.1" . "../lib/srfi/1.scm"))
;; acons
が呼ばれるのとは逆順のリストが
;; 返ることに注意してください
(library-fold 'srfi.1 acons '() :allow-duplicates? #t)
⇒ ((srfi.1 . "/usr/share/gauche-0.98/0.9.13/lib/srfi/1.scm")
(srfi.1 . "../lib/srfi.1.scm"))
;; 利用可能な dbm の実装を見付けます
(library-fold 'dbm.* acons '())
⇒ ((dbm.cdb . "/usr/share/gauche-0.98/0.9.13/lib/dbm/cdb.scm")
(dbm.gdbm . "../lib/dbm/gdbm.scm")
(dbm.ndbm . "../lib/dbm/ndbm.scm")
(dbm.odbm . "../lib/dbm/odbm.scm"))
マッチしたライブラリ/モジュール上のイテレータの map
版および
for-each
版。照合操作とキーワード引数の詳細については上述の
library-fold
を参照してください。
procは、マッチしたモジュール/ファイル名と、そのファイルの
フルパスの 2 つの引数をうけとります。library-for-each
は
結果を捨てます。
(library-map 'srfi.4 list :allow-duplicates? #t) ⇒ ((srfi.4 "../lib/srfi/4.scm") (srfi.4 "/usr/share/gauche-0.98/0.9.13/lib/srfi/4.scm")) (library-map 'dbm.* (lambda (m p) m)) ⇒ (dbm.odbm dbm.ndbm dbm.gdbm dbm.cdb)
mod/path で指定されたライブラリあるいはモジュールを検索し、
もしあれば、真値を返します。キーワード引数 paths および
strict? は library-fold
のそれと同じ意味です。
上述のイテレータ手続きとはちがい、この手続きは呼び出しの過程で
最初に既にロードされているライブラリおよびモジュールをチェックします。
もしそのときに mod/path を見つけたら、真値を返し、ファイル
システムを見にいくことはありません。キーワード引数 force-search?
に #t
を渡せば、すでにロードされいるライブラリおよびモジュール
のチェックはスキップされます。
path で指定したファイルが存在し、かつ、module
で名指しされた
モジュールが実装されている場合でその場合に限り、#t
を返します。
path は実際のファイル名でなければなりません。
(library-has-module? "./test/foo/bar.scm" 'foo.bar)
⇒ #t ;; if ./test/foo/bar.scm implements module foo.bar.
この手続きは典型的なソースコードの配置を仮定して、与えられたファイルが
そのモジュールを実装しているかどうかを決定します。すなわち、
まずそのコードのフォームを読み、与えられたモジュールを定義している
define-module
フォームかどうかを見ます。