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
というファイルを
あらわすのに使います。