このサーバのわたしのdisk quotaは小さく、少し大きな文書を置くと
すぐに使い切ってしまいますので、現在次のサーバに移行しつつあり ます。
http://www.dinukai.org/programming/scheme/.
今後の更新は上記サーバにて行なうつもりです。

Scheme、Scheme処理系、SCM

-> 英語

-> フランス語

更新:2004年12月22日 水曜日 01:24:01 JST

目次

Scheme

Schemeは、プログラミング言語Lisp(List Processing programming language)の方言の1つです。Lispプログラムは主として値を返す手続き(関 数)で構成されますので、関数型言語と呼ばれています。最終的な成果はプ ログラムですので、プログラミング言語を関数型と手続き型に分類すること 自体にはあまり意味はありません。Lispの考え方はC言語などにも存在して おり、発想に特別奇異なものもないのですが、現実にはLispで発想するプロ グラマは少いようです。

"Lisp as an Alternative to Java -- Erann Gatt, Jet Propulsion Laboratory, California Institute of Technology"という文献があります。 日付は1999年11月9日です。Lispプログラムの実行速度はCで注意深く書かれ た最高速のものには劣るけれどもC++と同等もしくはそれ以上、Javaスクリ プトよりも高速で、プログラムごとの性能の変動はC++よりも著しく少かっ たというデータが示されています。Lispプログラムのメモリ消費量はJavaと 同程度でしたが、実験結果がプログラマの熟練度に依存しておらず、プログ ラムの開発期間がC/C++やJava に比べて著しく短かったことも同時に報告さ れています。マシン語にコンパイルしたLispプログラムが使用されましたの で実行速度については割り引いて考えなければいけませんが、それ以外の特 徴はLispインタープリタにも当てはまると思われます。

Lispに愛着を持つ人々にとってこのような結果は当然で、Lispが優れたプロ グラミング言語であることは確信となっていますが、ならばLispがなぜ普及 しないのかが謎です。この謎を解き明かすのには時間がかかりそうですし、 あるい不可能かも知れません。Shiro Kawaiさんの Practical Schemeのように、実践して示すのが最善と思われます。

Schemeは、プログラミングに必要充分な機能を備えたLisp方言の中 でもっともコンパクトに設計された言語です。Schemeの仕様書は索 引を含めてa4版で50ページです。SchemeがLispであるためでもあり ますが、これほど小さな仕様で定義されたプログラミング言語は類を見ませ ん。Schemeに比べると他の言語は、円を手に入れようとして多角形 の辺の数を限りなく増やそうとしているように見えます。

Schemeの仕様が極めて明解ですので、Schemeプログラムはプ ログラミングを始めた初期の段階から、簡潔で正しく、美しいものになるこ とが保証されています。

Schemeは、「プログラミング言語は機能の上に機能を積み重ねるの ではなく、機能の追加を必要と思わせるような弱点と制限を取り除いて設計 すべきである」として、Lispの機構と構文を使用して作成されました。言語 仕様は、「実用的で効率のよいプログラミング言語を作成するためには、式 を組み立てる方法に制約がなければ極めて少数の式構成規則で足りる」と考 え抜いて設計されています(Revised5 Report on the Algorithmic Language Scheme--r5rs--Introduction)。

規則が正しければ、その規則にしたがうプログラムは正しいものになります。 必要充分な規則の数が少ければ、規則の適用範囲は広いものになります。プ ログラミング言語の規則はプログラムを表現する方法を規定するものですか ら、これはScheme の表現力が多様になることを意味します。しかも Schemeの規則に則る以上、Schemeにしたがって表現された多 様なプログラム1つ1つは、正しい明瞭なものにしかなり得ないことになりま す。

Schemeがはじめて文献に現れたのは、1975年に遡ります。Guy Lewis Steele Jr. と Gerald Jay Sussmanによって発明されました。Guy Lewis Steele Jr. は、「Common Lisp Reference Manual(First edition-1984, Second edition-1989)--Digital Press」の著者でもあり、Common Lispはあ る程度Schemeの影響も受けているとその序文の中で書いています。

Schemeの仕様は、Common Lispの研究成果を取り入れるなどの数度の 改訂を経て、「Revised4 Report on the Algorithmic Language Scheme--r4rs-1991」でほぼ固まりました。現在のScheme処理系のほ とんどは、すくなくともr4rsに準拠しています。

Schemeの最新の仕様は、「 Revised5 Report on the Algorithmic Language Scheme--r5rs-1998」で定められています。r5rsはr4rsの上位セットで す。

r5rsの拙訳を プ ログラミング言語Schemeに置いていただいています。
拙訳はわたし自身がScheme を使う必要に迫られたときに、Schemeに関す る日本語の文献を見つけることができないままに、もともとはわたし自身 のために訳出したものでした。書いたプログラムがわたしが理解したr5rs の通りに動作することから、拙訳に大きな誤りはなかろうと考えて公表し たものです。今読み返すと不備な点がたくさんありますが、1度公表して しまったので、翻訳をやり直す気になかなかなれません。便覧として使っ ていただければ幸いです。
その後r4rsとr5rsには他にも多くの日本語訳があることがわかりました。原 典はわたしにはかなりわかりにくいものでしたが、いろいろな翻訳を原典 とつき合わせることで、r5rsの理解も進むと思います。

Schemeは上に書いたような特徴からまず教育用の言語として普及 しましたが、それに止まるものではありません。このページでは、 Schemeの実用面をわたしの手が届く範囲で充実させていくつもり です。

Scheme処理 系

Schemeを実際に使うためにはScheme処理系をインストールす る必要があります。
Schemeには処理系がたくさんありますが、わたしたちがScheme を使 うにあたってもっとも気になるのが、日本語の処理です。Scheme 処理系がC で書かれている場合、char?が#tを返すSchemeの文字型には、C のchar型が 使われています。処理系が日本語localeをサポートする必要は必ずしもあり ませんが、日本語文字のような連続する2バイトが常に独立したバイトとし て処理された場合、2バイト文字は、加工はできますが入力と表示ができま せん。
わたしが使用した処理系で日本語の入力と表示ができるものは、使用頻度順に (1)SCM、(2)Gauche、(3)STklos (4)STk、(5)guile、(6)mit-schemeでした。特に GaucheではSchemeの文字列処理手続きが自然な形で拡張されて おり、使用する文字コード系をコンパイル時に指定すれば、標準の文字列処理 手続きでマルチバイト文字を処理できるようになります。

わたしが使用しているOSは、これも使用頻度順に、FreeBSD 6.0-CURRENT、 FreeBSD 5.3-STABLE、Debian Linux Unstable (kernel 2.4.26)、 Woody 3.0 (kernel 2.4.26)、Windows 2000です。ユーザの数から見ると、これは 丁度逆順になるようです。

それぞれにどのようにインストールしたかを次の表にまとめてみました。

わたしがインストールできたScheme処理系
OS SCM Gauche stklos STk guile mit-scheme
FreeBSD* 6.0-CURRENT**/5.3-STABLE*** rpmまたはgmake && ./build configure && make** configure && make configure && make ports collection binary
Debian Linux Unstable****/Woody(3.0r)***** rpmまたはmake configure && make configure && make configure && make apt-get install binary
Windows 2000****** make configure && make or binary / / / /

x ...インストールできませんでした。
/ ...インストールしていません。

* 現在(6.0-CURRENTと5.3-STABLE)はシステムのCコンパイ ラーに過渡的な問題があり、SCMをportsからインストールしようとし てもbrokenマークが付けられてインストールできないように見えてい ます。/usr/ports/lang/scm/Makefileを書き換えてbroken行を外し、 makeに引数を渡してコンパイルすれば動作するSCMを作成できますの で、次を参照して下さい
http://www.freebsd.org/cgi/query-pr.cgi?pr=ports/71684
** 6.0-CURRENT
% cc -v
Using built-in specs.
Configured with: FreeBSD/i386 system compiler
Thread model: posix
gcc version 3.4.2 [FreeBSD] 20040728

% gcc34 -v
Reading specs from /usr/local/lib/gcc/i386-portbld-freebsd6.0/3.4.3/specs
Configured with: ./..//gcc-3.4-20041105/configure --disable-nls --with-system-zlib --with-libiconv-prefix=/usr/local --program-suffix=34 --with-gxx-include-dir=/usr/local/lib/gcc/i386-portbld-freebsd6.0/3.4.3/include/c++/ --disable-shared --prefix=/usr/local i386-portbld-freebsd6.0 Thread model: posix
gcc version 3.4.3 [FreeBSD]

*** 5.3-STABLE
% cc -v
Using built-in specs.
Configured with: FreeBSD/i386 system compiler
Thread model: posix
gcc version 3.4.2 [FreeBSD] 20040728

% gcc34 -v
Reading specs from /usr/local/lib/gcc/i386-portbld-freebsd5.3/3.4.3/specs
Configured with: ./..//gcc-3.4-20041029/configure --disable-nls --with-system-zlib --with-libiconv-prefix=/usr/local --program-suffix=34 --with-gxx-include-dir=/usr/local/lib/gcc/i386-portbld-freebsd5.3/3.4.3/include/c++/ --disable-shared --prefix=/usr/local i386-portbld-freebsd5.3
Thread model: posix
gcc version 3.4.3 20041029 (prerelease) [FreeBSD]

**** Debian Linux Unstable Version
% cc -v Reading specs from /usr/lib/gcc-lib/i486-linux/3.3.4/specs
Configured with: ../src/configure -v --enable-languages=c,c++,java,f77,pascal,objc,ada,treelang --prefix=/usr --mandir=/usr/share/man --infodir=/usr/share/info --with-gxx-include-dir=/usr/include/c++/3.3 --enable-shared --with-system-zlib --enable-nls --without-included-gettext --enable-__cxa_atexit --enable-clocale=gnu --enable-debug --enable-java-gc=boehm --enable-java-awt=xlib --enable-objc-gc i486-linux
Thread model: posix
gcc version 3.3.4 (Debian 1:3.3.4-4)
***** Debian Linux Woody (3.0r)
% cc -v Reading specs from /usr/lib/gcc-lib/i386-linux/2.95.4/specs
gcc version 2.95.4 20011002 (Debian prerelease)
****** Windwos 2000にはcygwin環境を使用してイン ストールしました。
cygwin環境はhttp://sources.redhat.com/cygwin から入手できます。
- 浮動小数点数の精度について。x86系cpuとgccを組み合わせたとき のgccのあやしい振舞いについて、 川合さんが詳しく考察しています。
浮動小数点数の処理については、入出力の精度に不満を残す 処理系が多いようです。

例: (/ 1448997445238699 (expt 10 15)) ≒ 1.448997445238699と(* 6525704354437806 (expt 2 -52))。

Shiro Kawaiさんから、"Printing Floating-Point Numbers Quickly and Accurately", Robert G. Burger and R. Kent Dybvig, Proceedings of the SIGPLAN '96 Conference on Programming Language Design and Implementation. という論文の存在を教えてい ただきました。この論文では、浮動小数点数の高速で正確な出力を 実装するアルゴリズムが述べられており、Chez Schemeを使用してア ルゴリズムの正当性が確認されています。R. Kent Dybvig氏がChez Schemeの開発に主として携わっていることから、Chez Schemeにはこ のアルゴリズムが実装されているようです。
ただしここに紹介する処理系はformatのような拡張出力モジュールを 備えているか、あるいはSLIBのprintfが使えますので、出力精度を気 にする必要はないと思います。

SCMについて

SCMを使うためには、Schemeで書かれたライブラリ SLIBをあらかじめインストールして、SCMから呼び出せるようにして おく必要があります。

SLIB

SLIBhttp://swissnet.ai.mit.edu/~jaffer/SLIB.html から入手できます。現在のバージョンは「3a1(2003-11-03)」です。Aubrey Jafferさんが保 守しています。SLIBを最新のものに更新すると同時にSCMの バージョンも同期させておいた方がいいと思います。

slib2d6.zipを入手したら書き込み権限がある適当なディレクトリ、例えば' /usr/local/lib' に展開します。


    % unzip slib3a1 -d /usr/local/lib
  
SLIBライブラリは、指定したディレクトリの下の、slibディレクト リに展開されます。このディレクトリを、セッションの環境設定ファイルで 環境変数'SCHEME_LIBRARY_PATH'に指定しておきます。あとでライブラリファ イル名を環境変数に連結する必要がありますので、最後にフォワードスラッ シュ(Windowsでは円記号)が必要です。

書き込み権限があるディレクトリにSCMSLIBをインストー ルする限りは問題にならないと思いますが、環境が自由にならない場合は、 SCMをインストールしたディレクトリ内にrequire.scmを作成して、 中に


    (set! library-vicinity (lambda () "/compat/linux/usr/share/slib/"))
  
のように、SLIBが存在するディレクトリを直接書いておいてもいい です。

SCMのインストール

  1. 入手したscm5d9.zipを適当なディレクトリ、例えば$HOMEに展開します。 SCMは、指定したディレクトリの下のscm ディレクトリに展開されます。
    
        unzip scm5d9 -d $HOME
        
  2. SCMのコンパイルにとりかかる前に、次を修正しておいた方がいいかもし れません。

    • bignumデータ形式の使用

      SCMのbignumデータ形式を有効に使うためには、scmfig.hで定義され ているNUMDIGS_MAXを20000桁程度にし ておいた方がいいと思います。自前のMakefileでコンパイルする場合 は、コンパイラに-DNUMDIGS_MUX=20000を渡してもいいです。
      SCMセッションのプロンプトに表示する文字列もこのファイルで変更 できます。

  3. scmlitを作成します。
    
          make scmlit (FreeBSDではgmake scmlit -- GNU makeを使用)
          
    - scmlitは、Schemeで書かれたスクリプトファイルbuildを実 行するために作成します。
    scmlitはbuildスクリプトを実行するために必要な最小限のモジュー ルだけで構成されていますので、どのOSでもコンパイルできる可能性 が高くなっています。
  4. scmlitが作成できれば、Linuxの場合はmake allでコンパイルできま す。ただしデフォルトでは、r5rsマクロを組み込んだ実行イメージを ダンプしたSCMが作成されます。Linuxでイメージダンプファイルを使 いたくない場合とFreeBSDでは、buildスクリプトを使って実行ファイ ルを作成できます。

    buildの引数には、-p freebsdのような短形式と、 --platform=freebsdのような長形式がありますが、ここでは短形式だ けを紹介します。詳しくはscmディレクトリに展開されるinfoファイ ルから、scm -- Installing SCM -- Building SCM -- Build Options を参照して下さい。

    • -h バッチスクリプトの形式
      バッチスクリプトの形式には、unix、dos、vms、amigados、system のいずれかを指定できます。
      -h systemを指定すると、実際にコンパイルが行なわれます。それ 以外の指定では、それぞれのOSに応じたバッチスクリプトが、標準 出力に出力されます。SCMは実際にはbuildを実行する環境からバッ チスクリプトの形式を判断しますので、systemを指定するのでなけ れば-hオプションは不要です。
    • -p プラットフォーム
      プラットフォームには、buildデータベースが持っているプラット フォーム名を指定します。ここで使用するのは、freebsd、linux、 os/2-emx、unix(cygwin用)のいずれかです。
      これによりbuildデータベースから、プラットフォーム固有のコンパイ ルオプションとリンクオプションが選択されます。
    • -t 作成するオブジェクトの種類(type)。
      • exe
        実行形式プログラム。
      • lib
        ライブラリモジュール。
      • dlls
        すべてのダイナミックリンクリンクライブラリオブジェクトファイル。
      • dll
        特定のダイナミックリンクライブラリオブジェクトファイル。
      デフォルトでは実行形式ファイルが作成されます。
    • -F 機能名 ...
      -Fオプションの機能名には、次の表に示す機能名を空白で区切って 指定します。表中*(アスタリスク)で印をつけた機能は上記コンパ イル環境でわたしがコンパイルできなかったものです。機能名に対 応する機能の詳細についてはscm.infoとソースファイルを参照して 下さい。

      コンパイル可能なSCMの機能(d = ダイナミックリンクライブ ラリ、o = できた、 * = できなかった、 / = テストしていない)
      機能名 機能の概要 動的ロード可 FreeBSD Debian Linux cygwin
      arrays 多次元配列 o o o
      array-for-each arrayのマッピング o o o
      bignums 多倍長整数 o o o
      cautious 手続きに渡される引数のチェック o o o
      compiled-closure C関数の組み込み o o o
      curses cursesライブラリの組み込み d o o o
      debug デバグ用エラーチェック o o o
      dump 実行イメージダンプ * o *
      dynamic-linking dlライブラリの使用 o o *
      edit-line ラインエディタ d o o /
      engineering-notation エンジニアリング表記の使用 o o o
      generalized-c-arguments 可変引数C関数の使用 d o o o
      i/o-extensions ANSI CファイルI/O d o o *
      inexact 浮動小数点数の組み込み o o o
      macro r5rsマクロのサポート o o o
      posix posix関数(pipe,fork,uname etc.) d o o o
      unix posix以外のunix関数(symlink,nice,mknod etc.) d o o *
      record レコードデータ型 d o o o
      regex 正規表現 d o o *
      rev2-procedures r2rs手続き d o o /
      sicp (eq? () #f)==>#t, etc / / /
      socket BSDソケット d o o /
      tick-interrupts ticks, ticks-interrupt, alarm etc. o o o

      - dynamic-linkingはlibdlを使用します。libdlは、Linuxでは 独立したライブラリファイルですが、FreeBSDではlibcに入って います。
      - i/o-extensionsはスタティックに組み込むことも、dlとして ロードすることもできます。別のライブラリがこれの使用を前提 にしている場合があるので、読み込まれていないと(load "ライ ブラリ")が失敗することがあります。(require '機能)を使用すれ ば、必要に応じてioext.soが先にダイナミックロードされます。
      - edit-lineは、外部ライブラリlibreadlineを使用します。ター ミナルモードでインタラクティブにSCMを使いたいとき に便利です。libreadlineの日本語対応が不適切だったりして ラインエディタを使いたくない場合は、edit-lineを使わなけ ればいいだけです。emacsやxemacsのサブプロセスとして SCMを呼び出したときはedit-lineは使用されず、emacs の編集機能でインタラクティブに操作することができます。

    スクリプトとして使用するときは実行ファイルは小さいほど読み込みが 速く行なわれるので、ダイナミックリンクライブラリの受け口を取り付 けた最小のscmを作っておいて、必要に応じてライブラリを動的にロー ドする方が小回りが効いて便利です。

    buildを-Fなしで実行した場合は、デフォルトでarrays、bignums、inexactだけを指定したscmが作成されます。
    
          buildの実行例1
            ./build -h system -p freebsd 
          
    この指定によって汎用的で最小のScheme処理系が作成されます が、拡張機能を動的にロードできないので不便を感ずることがあります。

    次は1にダイナミックリンクライブラリの受け口を取り付けたscmを 作成する場合です。-Fを指定したときには指定した機能だけが組み込まれ るようになるので、必要な機能をすべて明示的に指定する必要がありま す。

    
          buildの実行例2
            ./build -h system -p freebsd -F arrays bignums inexact dynamic-linking
          
    わたしは次のようにしています。
    
          buildの実行例3
            ./build -h system -p freebsd -F arrays array-for-each bignums cautious compiled-closure dynamic-linking inexact i/o-extensions macro tick-interrupts
    
          
    これで作成されるファイルの大きさは345227バイトで、stripすると 307508バイトになります。このプログラムで、r5rs仕様のほとんどすべ てをカバーしています。
  5. ダイナミックリンクライブラリを作成します。
    
            ./build -h system -p freebsd -t dlls
    
          
  6. r4rstest.scmを 実行して、作成したSCMの動作を確認します。
    
        ./scm r4rstest
        SECTION(2 1)
        SECTION(3 4)
         #<;primitive-procedure boolean?>;
         ...
       Passed all tests
    
       To fully test continuations, Scheme 4, and DELAY/FORCE do:
       (test-cont) (test-sc4) (test-delay)
       SCM> (test-cont) (test-sc4) (test-delay)
       ...
       Passed all tests
       ...
       (exit)
        
  7. syntest1.scmを 実行して、r5rsマクロの動作を確認します。
    
        ./scm -l syntest1
         (let ((x (quote outer))) \
           (let-syntax ((m (syntax-rules () ((m) x)))) \
             (let ((x (quote inner))) (m)))) ==> outer
         (let-syntax 
            ((when 
              (syntax-rules () \
              ((when ?test ?stmt1 ?stmt2 ...) (if ?test (begin ?stmt1 ?stmt2 ...)))))) \
            (let ((if #t)) (when if (set! if (quote now))) if)) ==> now
         ...
         (define-syntax replic \
            (syntax-rules () \
             ((_ (?x ...) (?y ...)) (let ((?x (list ?y ...)) ...) (list ?x ...)))))
         (replic (x y z) (1 2)) ==> ((1 2) (1 2) (1 2))
    
         Passed all tests
         Load "syntest2" to rewrite derived expressions and test
        
  8. syntest2.scmを 実行して、r5rsキーワードを再定義してみます。
    
        ./scm -l syntest2
    
        ;While loading "syntest2.scm", line 53: \
        WARNING: "/home/scm/Macro.scm": redefining built-in syntax let
        ...
    
        ;While loading "syntest2.scm", line 182: \
        WARNING: "/home/scm/Macro.scm": redefining built-in syntax quasiquote
        
  9. インストール

    インストールはMakefileの中で指定されているprefixディレクトリに行な われ、SCMが使用するライブラリのカタログファイル(implcatと slibcat)もそこに書き込まれますので、ディレクトリに対する書き込み権 限が必要です。スーパーユーザでインストールを実行するか、でなけれ ばご自分が権限を持つディレクトリをprefixに指定しておきます。

    
        make install (prefix=$HOME/)
        

    実行ファイルが、Makefileの中で指定されているprefixディレクトリの下 のbinディレクトリに、Init$(VERSION).scmその他の初期化ファイルが $(prefix)/lib/scmディレクトリにインストールされます。ダイナミック ロードライブラリ(*.so)を作成していれば、それも同じディレクトリにイ ンストールされます。

    スーパーユーザのままでインストール後にSCMを実行すると、カタ ログファイルがscmディレクトリに作成されます。Schemeの世界を 楽しんで下さい。

-> ひとつ前へ

-> ホーム


犬飼 大