Scheme のメージャな方言はどれも、R5RS の仕様[cite{r5rs}] を 実装しています。R5RS に記述されている機能だけを使って、こうした 方言間でポータブルな Scheme のコードを書くことができます。 しかし、R5RS はコンセンサスの欠如や回避できないシステム依存性 のために自明でないプログラミングで無視できない、いくつかの問題に ついては沈黙しています。それ故、さまざまな方言が、非標準で、固有の 方法でこれらの問題に対応しています。
この文書では、MzScheme [cite{mzscheme}] という Scheme の方言を
使っています。それにともなって、非標準の機能もいくつか使用しています。
この文書で使われている、方言依存の機能の完全なリストは、
コマンドライン(リスナーセッションの開始とシェルスクリプトの両方)、
define-macro、delete-file、file-exists?、
file-or-directory-modify-seconds、fluid-let、
gensym、getenv、get-output-string、
load-relative、open-input-string、
open-output-string、read-line、reverse!、
system、unless、when です。
これらのうち二つをのぞけば、どれも MzScheme のデフォルトの環境で
あるものです。ないもの二つというのは、define-macro および system
で、MzScheme の標準ライブラリで提供されています。これらは
以下のフォームを使って、明示的にMzSchemeにロードすることができます。
(require (lib "defmacro.ss")) ;define-macro を提供 (require (lib "process.ss")) ;system を提供
これらのフォームを置く良い場所は、MzScheme の初期化ファイル
(あるいはinit ファイル)で、Unix ではユーザのホーム
ディレクトリの .maschemerc ファイルです。1
非標準機能のうちのいくつか(たとえば、file-exists?、delete-file)
は実際にはデファクトスタンダードで多くの Scheme で提供されています。
それ以外の機能のいくつか(たとえば、when、unless)は、
早晩、それらをプリミティブとしていない Scheme 方言のどれにでも、
ロード可能な「プラグイン」定義(この文書で与えた)があります。
のこりは、方言特有の定義があります(たとえば、load-relative)。
本章では、お使いの Scheme 方言に、この文書で使っている、非標準の機能 を組み込む方法を解説します。お使いの Scheme 方言について、さらに詳しくは、 実装者(付録 E)が提供している文書にあたってください。
MzScheme と同様に、多くの Scheme 方言は、可能であれば、init ファイルを
ロードします。この init ファイルは通常ユーザのホームディレクトリに
置かれます。この init ファイルは非標準の機能の定義を置く場所として
便利です。たとえば、非標準手続き file-or-directory-modify-seconds を
Scheme の Guile [cite{guile}] 方言に追加するには、以下のコードを Guile
の init ファイル ~/.guile に置いておけば可能です。
(define file-or-directory-modify-seconds (lambda (f) (vector-ref (stat f) 9)))
また、いろいろな Scheme 方言はそれぞれの別の名前のリスナー起動 コマンドを持っています。以下の表は、いくつかの Scheme 方言の 起動コマンドと init ファイルです。
| Dialect name | Command | Init file |
| Bigloo | bigloo | ~/.bigloorc |
| Chicken | csi | ~/.csirc |
| Gambit | gsi | ~/gambc.scm |
| Gauche | gosh | ~/.gaucherc |
| Guile | guile | ~/.guile |
| Kawa | kawa | ~/.kawarc.scm |
| MIT Scheme (Unix) | scheme | ~/.scheme.init |
| MIT Scheme (Win) | scheme | ~/scheme.ini |
| MzScheme (Unix, Mac OS X) | mzscheme | ~/.mzschemerc |
| MzScheme (Win, Mac OS Classic) | mzscheme | ~/mzschemerc.ss |
| SCM | scm | ~/ScmInit.scm |
| STk | snow | ~/.stkrc |
Guile で書いたシェルスクリプトの最初の一行は以下のようになります。
":";exec guile -s $0 "$@"
このスクリプトでは、手続き呼び出し (command-line) は
スクリプトの名前と引数のリストを返します。引数にだけアクセス
したいのであれば、このリストの cdr をとればいいだけです。
Gauche [cite{gauche}] のシェルスクリプトの最初はこんな風になります。
":"; exec gosh -- $0 "$@"
このスクリプトでは、変数 *argv* がスクリプトへの引数のリストを
保持しています。
SCM で書いたシェルスクリプトはこんな感じです。
":";exec scm -l $0 "$@"
このスクリプトでは、変数 *argv* に Scheme の実行ファイル名、
スクリプトの名前、オプション -l、それにスクリプトへの引数が
含まれています。引数にだけアクセスしたいのであれば、このリストの
cdddr をとればいいです。
STk [cite{stk}] のシェルスクリプトの最初は以下のとおり。
":";exec snow -f $0 "$@"
このスクリプトでは、変数 *argv* がスクリプトへの引数のリストを
保持しています。
define-macro
このテキストでは使われている define-macro は Scheme の方言
Bigloo [cite{bigloo}]、Chicken [cite{chicken}]、Gambit[cite{gambit}]、
Gauche [cite{gauche}]、Guile、MzScheme および
Pocket Scheme [cite{pocketscheme}] にあらわれます。
(define-macro MACRO-NAME (lambda MACRO-ARGS MACRO-BODY ...))
MIT Scheme [cite{mitscheme}] version 7.7.1 およびそれ以降では これは以下のように書かれます。
(define-syntax MACRO-NAME (rsc-macro-transformer (let ((xfmr (lambda MACRO-ARGS MACRO-BODY ...))) (lambda (e r) (apply xfmr (cdr e))))))
それより前のバージョンの MIT Scheme では以下のようになっています。
(syntax-table-define system-global-syntax-table 'MACRO-NAME (macro MACRO-ARGS MACRO-BODY ...))
SCM [cite{scm}] および Kawa [cite{kawa}] では以下です。
(defmacro MACRO-NAME MACRO-ARGS MACRO-BODY ...)
STk [cite{stk}] では以下です。
(define-macro (MACRO-NAME . MACRO-ARGS) MACRO-BODY ...)
load-relative手続き load-relative は Guile では以下のように定義できます。
(define load-relative (lambda (f) (let* ((n (string-length f)) (full-pathname? (and (> n 0) (let ((c0 (string-ref f 0))) (or (char=? c0 #\/) (char=? c0 #\~)))))) (basic-load (if full-pathname? f (let ((clp (current-load-port))) (if clp (string-append (dirname (port-filename clp)) "/" f) f)))))))
SCM では以下です。
(define load-relative (lambda (f) (let* ((n (string-length f)) (full-pathname? (and (> n 0) (let ((c0 (string-ref f 0))) (or (char=? c0 #\/) (char=? c0 #\~)))))) (load (if (and *load-pathname* full-pathname?) (in-vicinity (program-vicinity) f) f)))))
STk では、以下の load-relative の定義は load を使わない
ようにしているときにのみちゃんと働きます。
(define *load-pathname* #f) (define stk%load load) (define load-relative (lambda (f) (fluid-let ((*load-pathname* (if (not *load-pathname*) f (let* ((n (string-length f)) (full-pathname? (and (> n 0) (let ((c0 (string-ref f 0))) (or (char=? c0 #\/) (char=? c0 #\~)))))) (if full-pathname? f (string-append (dirname *load-pathname*) "/" f)))))) (stk%load *load-pathname*)))) (define load (lambda (f) (error "Don't use load. Use load-relative instead.")))
1 ~/filename という
記法をユーザのホームディレクトリにある filename というファイルを
あらわすのに使います。