TinyScheme
TinyScheme は、Scheme の R5RS のサブセットを可能な限り大規模かつ複雑にならないように実装した軽量な Scheme インタープリタ。 BSDスタイルのオープンソースライセンスになっている。
TinyScheme は、他のプログラムの組み込み用スクリプトインタープリタとして使用されることが想定されていているため、IDE や大規模なツールキットは提供されていないものの、条件付きで小さなトップレベルループが含まれている。GIMP で使われているのが有名。 TinyScheme の多くの機能は、開発者が機能とフットプリントのバランスを自由に取れるように、条件付きで提供されている。
組み込み型インタプリタであるため、複数のインタプリタ状態を同一プログラム内に共存させることができ、インタプリタ間の干渉がない。 プログラム的には、C言語の外部関数を追加したり、Scheme 環境下で値を定義したりすることが可能。 非常に小さなプログラムなので、理解しやすく、取っつきやすく、使いやすい。
TinySchemeは、Ovrimosの開発中に、MiniScheme ディストリビューションから発展してきた経緯があるらしい。
- オフィシャルサイト: http://tinyscheme.sourceforge.net/
- 関連:Scheme R5RSのドキュメント日本語訳 - https://www.unixuser.org/~euske/doc/r5rs-ja/r5rs-ja.pdf
Manual の適当翻訳
TinySCHEME Version 1.41 "Safe if used as prescribed" "処方通りに使用すれば安全" -- Philip K. Dick, "Ubik" このソフトウェアは、BSDスタイルのライセンスで保護されたオープンソースです。 付属のファイル COPYING をお読みください。 ------------------------------------------------------------------------------- This Scheme interpreter is based on MiniSCHEME version 0.85k4 (see miniscm.tar.gz in the Scheme Repository) Original credits in file MiniSCHEMETribute.txt. このSchemeインタープリタは、MiniSCHEME version 0.85k4 に基づいています。 (Schemeリポジトリにあるminiscm.tar.gzを参照) オリジナルのクレジットはファイルMiniSCHEMETribute.txtにあります。 D. Souflis (dsouflis@acm.org) ------------------------------------------------------------------------------- TinySchemeとは? ---------------- TinySchemeは、R5RSのサブセットを可能な限り大規模かつ複雑にならないように 実装した、軽量なSchemeインタープリタです。他のプログラムの組み込み用 スクリプトインタープリタとして使用されることを想定しています。そのため、 IDEや大規模なツールキットは提供されていませんが、条件付きで小さなトップ レベルループが含まれています。 TinyScheme の多くの機能は、開発者が機能とフットプリントのバランスを自由に 取れるように、条件付きで提供されています。 組み込み型インタプリタとして、同一プログラム内に複数のインタプリタ状態を 共存させることが可能であり、インタプリタ間の干渉がない。 プログラム的には、C言語の外部関数を追加したり、Scheme環境下で値を定義 したりすることができます。非常に小さなプログラムなので、理解しやすく、 取っつきやすく、使いやすい。 既知のバグ ---------- TinySchemeは、メモリを使い切ると誤動作することが知られています。 不足しがちなもの、修理が必要なもの ---------------------------------- 衛生的なマクロはない。有理数、無理数 複素数。unwind-protectと call-with-valuesがない。 もしかしたら SLIB の(サブセット)が TinySCHEME で動くかもしれませんが...。 まともなデバッギング機能がない。トレースのみサポート ネイティブです。 Scheme リファレンス ------------------- もし、足りないものがあるようでしたら、コードと 「init.scm "は、 ライブラリ関数である場合があります。 MiniSCHEME 最後の手段として、readme をお読みください。 環境 (interaction-environment) R5RSを参照。TinySCHEME では、関連リストの不変リスト。 (current-environment) 実行時の環境です。その使用例と有用性は、"init.scm "のパッケージを 実装したサンプルコードで確認することができます。 (macro (package form) `(apply (lambda () ,@(cdr form) (current-environment)))) クロージャ内の(ローカルな)定義を含む環境が、イミュータブルな値 として返される。 (defined? symbol) (defined? symbol environment) 与えられたシンボルが現在の(あるいは与えられた)環境で定義されて いるかどうかをチェックします。 シンボル (gensym) 毎回、新しいインターン先のシンボルを返します。string-symbol が 実装されたら、ライブラリに移動するかもしれません。 ディレクティブ (gc) ガベージコレクションを即座に実行します。 (gcverbose) (gcverbose bool) 引数(デフォルトは#t)は、GCが可視結果を生成するかどうかを制御します。 (quit) (quit num) インタプリタを停止し、内部フィールド 'retcode' を設定する (デフォルトは 0)。 スタンドアロンでは、'retcode' は OS への終了コードとして返される。 (tracing num) 1, turns on tracing. 0 turns it off. (Only when USE_TRACING is 1). 数学的関数 有理数や複素数がないため、それぞれの関数もない。 USE_MATH=1 のときに利用可能な関数 : exp, log, sin, cos, tan, asin, acos, atan, floor, ceiling, trunc, round sqrt expt 数理論理商 : remainder and modulo, gcd, lcm. ライブラリ : exact?, inexact?, odd?, even?, zero?, positive?, negative?, exact-inexact. inexact-exact is a core function. 型述語 boolean?,eof-object?,symbol?,number?,string?,integer?,real?,list?,null?, char?,port?,input-port?,output-port?,procedure?,pair?,environment?', vector?. Also closure?, macro?. 型 対応する種類 Numbers (integers and reals) Symbols Pairs Strings Characters Ports Eof object Environments Vectors リテラル表記 Stringリテラルには、通常通り "escape quotes \"を含めることができますが、 "escape quotes \n, \r, \t, \xDD (hex representation) と DDD (octal representation) "を含めることもできます。 また、文字列の中にリテラルな改行を含めることが可能です。 例えば (define s "改行がある文字列はこちら とここ のように機能することができます。") 文字リテラルは、#keyspace と #keynewline を含み、#return と #keytab で 補完され、明白な意味を持つ。16進文字表現も可能である(例: #keyx20 は #keyspace )。 USE_ASCII_NAMES を定義すると、各種制御文字を ASCII 名で参照することができる。 0 #\nul 17 #\dc1 1 #\soh 18 #\dc2 2 #\stx 19 #\dc3 3 #\etx 20 #\dc4 4 #\eot 21 #\nak 5 #\enq 22 #\syn 6 #\ack 23 #\etv 7 #\bel 24 #\can 8 #\bs 25 #\em 9 #\ht 26 #\sub 10 #\lf 27 #\esc 11 #\vt 28 #\fs 12 #\ff 29 #\gs 13 #\cr 30 #\rs 14 #\so 31 #\us 15 #\si 16 #\dle 127 #\del 数値リテラルは、#x #o #b と#d をサポートしています。fronum は 現在10進数表記でのみ読み取れます。完全な文法は近々サポートされる予定です。 Quote, quasiquote etc. いつも通りです。 不変の価値 不変なペアは、set-car! および set-cdr! によって変更できません。 不変の文字列は string-set! で変更できません。 I/O R5RSに準じ、String Ports(下記参照)を追加。 current-input-port, current-output-port, close-input-port, close-output-port, input-port?, output-port?, open-input-file, open-output-file. read, write, display, newline, write-char, read-char, peek-char. char-ready? は文字列ポートに対してのみ #t を返します。なぜなら、stdio には文字が利用可能かどうかを判断するポータブルな方法がないからです。 その他に open-input-output-file, set-input-port, set-output-port (not R5RS) ライブラリ: call-with-input-file, call-with-output-file, with-input-from-file, with-output-from-file and with-input-output-from-to-files, close-port and input-output-port? (not R5RS). 文字列のポート: open-input-string, open-output-string, get-output-string, open-input-output-string. 文字列は、I/Oルーチンで使用することができます。 ベクトル make-vector, vector, vector-length, vector-ref, vector-set!, list-vector, vector-fill!, vector-list, vector-equal? (補助機能, not R5RS) 文字列 string, make-string, list-string, string-length, string-ref, string-set!, substring, string-list, string-fill!, string-append, string-copy. string=?, string?, string?, string?, string=?, string=?. (No string-ci*? yet). string-number, number-string. Also atom-string, string-atom (not R5RS). シンボル symbol-string, string-symbol キャラクター(文字) integer-char, char-integer. char=?, char?, char?, char=?, char=?. (No char-ci*?) ペア & リスト cons, car, cdr, list, length, map, for-each, foldr, list-tail, list-ref, last-pair, reverse, append. Also member, memq, memv, based on generic-member, assoc, assq, assv generic-assoc に基づく。 ストリーム head, tail, cons-stream 制御機能 procedure? とは別に、macro? と closure? も map, for-each, force, delay, call-with-current-continuation (or call/cc), eval, apply. 約束でない値を「強制」すると、値が生成される。 ' 'Forcing' a value that is not a promise produces the value. call-with-values、values、dynamic-windはありません。連続性がある場合の dynamic-wind は、抽象機械自身によるサポートが必要です。 プロパティリスト TinyScheme - MiniScheme から継承したシンボルのプロパティ一覧です。 put, get. ダイナミックにロードされるエクステンション (load-extension 拡張子なしのファイル名) 外部手続きを宣言したDLLをロードする。Unix/Linuxでは、ld.so.conf ファイルや LD_RUN_PATHシステム変数を使って、ライブラリを現在のディレクトリ以外の場所に 配置することができる。適切な'man'ページを参照してください。 エソテリックの手続き (oblist) 全てのシンボルの不変リストである oblist を返します。 (macro-expand form) 引数で指定されたマクロ呼び出しの展開形を返します。 (define-with-return (procname args...) body) 通常の 'define' と同様ですが、プロシージャの内部で 'return' として継続を使用 できるようにします。命令型プログラムには便利。 (new-segment num) より多くのメモリセグメントを割り当てます。 defined? "環境" を参照 (get-closure-code closure) コードをスキームデータとして取得します。 (make-closure code environment) 与えられた環境で新しいクロージャを作成します。 廃止された手続き (print-width object) プログラマーズリファレンス -------------------------- インタープリターの状態は "scheme_init" で初期化されます。 カスタムのメモリ割り当てルーチンは、別の初期化関数でインストールする ことができます : "scheme_init_custom_alloc" scheme_load_file "でファイルを読み込むことができます。Scheme code を 含む文字列は "scheme_load_string" でロードすることができます。 init.scm を "scheme_load" するのは良い考えです。 外部状態を保持するための外部データ(外部関数が使用する)は "scheme_set_external_data" でインストールすることができる。 外部関数は "assign_foreign" でインストールされる。インタプリタ状態には、 "scheme_define" で追加の定義ができます (これはHTTPヘッダーデータとHTML フォームデータをAltera SQL Server内のSchemeスクリプトに渡す方法です)。 特定の環境で外部関数を定義したい場合(モジュール性を高めるため)は、 "assign_foreign_env" を使用します。 プロシージャ "scheme_apply0" は、永続的なスクリプトを念頭において 追加されたものである。永続的なスクリプトは一度ロードされると、HTTP出力を 生成する必要があるたびに、グローバル定義を通じて適切なデータが渡され、 関数 "main" が呼び出されて処理が行われます。scheme_apply1 "などと簡単に 追加することもできます。 インタプリタの状態は "scheme_deinit" で非初期化されるべきです。 外部関数を含む DLL は init_base-name という名前の関数を定義すべきです。 例えば、foo.dll は init_foo を定義し、bar.so は init_bar を定義すべきです。 この関数は、DLLに含まれるあらゆる外部関数を assign_foreign する必要があります。 TinyScheme で利用可能な最初の動的ロードされた拡張機能は、以下のとおりです。 正規表現ライブラリです。これは決して確立された標準ではありませんが、この ライブラリは TinyScheme の場所の下にその名前と同じディレクトリにインストール されることになっています。 外部向け機能 ------------- ユーザはC言語で外部関数を追加することができます。 例えば、関数引数を2乗するもの。 pointer square(scheme *sc, pointer args) { if(args!=sc-NIL) { if(sc-isnumber(sc-pair_car(args))) { double v=sc-rvalue(sc-pair_car(args)); return sc-mk_real(sc,v*v); } } return sc-NIL; } 外部関数はクロージャとして定義されるようになりました。 sc-interface-scheme_define( sc, sc-global_env, sc-interface-mk_symbol(sc,"square"), sc-interface-mk_foreign_func(sc, square)); 外部関数は、scheme 構造体の外部データを使用して、あらゆる種類の 外部状態を実装することができます。 外部データは、以下の機能で設定します : void scheme_set_external_data(scheme *sc, void *p); v.1.17以降では、DLL内の外部関数が Scheme データを操作する方法として、 sc-interface の関数ポインタを使用するのが一般的となっています。 スタンドアロン -------------- 使用 : tinyscheme -? or: tinyscheme [file1 file2 ...] その後に -1 file [arg1 arg2 ...] -c Scheme commands [arg1 arg2 ...] 実行ファイル名がtinyschemeであると仮定した場合。 使用 - stdin を表すファイル名の代わりに指定します。 -1 フラグは、シェルスクリプトで #! を使用するためのものです。指定を #! /somewhere/tinyscheme -1 とすると、tinyscheme が呼び出され、そのファイルを処理します。 たとえば次のようなものです。 次のスクリプトは引数の Scheme リストを表示します。 #! /somewhere/tinyscheme -1 (display *args*) -c フラグは、任意のSchemeコードの実行を許可します。 エラーハンドリング ------------------ エラーは無傷で回復します。ユーザーは *error-hook* を定義することに より、システムエラーのための独自のハンドラをインストールすることができます。 '() に定義すると、デフォルトの動作となり、"error" と同じになります。 USE_ERROR_HOOK を定義しておく必要があります。 簡単な例外処理機構は、"init.scm "にあります。 新しい構文形式が導入されました。 (catch expr returned exceptionally expr1 expr2 ... exprN) "Catch "は、別の "catch "に遭遇するまで、複数のコールフレームに またがるスコープを確立します。 例外が投げられます: (throw "message") (catch ...) の外で使用された場合、(error "メッセージ") に戻ります。 使用例: (define (foo x) (write x) (newline) (/ x 0)) (catch (begin (display "Error!\n") 0) (write "Before foo ... ") (foo 5) (write "After foo")) 例外機構は、システムエラーであっても、次のような方法で (define *error-hook* throw) であり,上記のエラーフックを利用したものです。 必要であれば、タグ付けされた例外など、ユーザー自身が例外の仕組みを 考案することもできます。 リーダー拡張機能 ----------------- '# の後に未知の文字があると、ユーザが指定した手続き *sharp-hook* (もしあれば) が呼ばれ、式が読み込まれます。 これは、ユーザー定義の定数などを扱うためにリーダーを拡張するのに使う ことができます。これは、現在の入力ポート (load-port) から読み込む、 引数のない手続きでなければならない。 コロン修飾子 - パッケージ --------------------------- USE_COLON_HOOK=1 のとき、 lexer は修飾子::記号という構文を認識し のように変換する(Tは変換関数)。 T(qualifier::symbol) = (*colon-hook* 'T(symbol) qualifier) ここで、qualifier はダブルコロンが含まれない記号です。 定義は再帰的であるため、修飾子は入れ子にすることができます。 ユーザは、修飾名を処理するために、独自の*colon-hook*を定義することができます。 デフォルトでは、"init.scm "は*colon-hook*をEVALとして定義しています。 したがって、修飾子は (interaction-environment) が返すような Scheme 環境を 示すものでなければなりません。「Init.scmは新しい構文形式を定義しています。 PACKAGEという新しい構文を定義しています。これは次のように使われます: (define toto (package (define foo 1) (define bar +))) foo == Error, "foo" undefined (eval 'foo) == Error, "foo" undefined (eval 'foo toto) == 1 toto::foo == 1 ((eval 'bar toto) 2 (eval 'foo toto)) == 3 (toto::bar 2 toto::foo) == 3 (eval (bar 2 foo) toto) == 3 ユーザーが別のパッケージ基盤をインストールする場合、提供されたコードとの 互換性を維持するために、新しい「パッケージ」プロシージャまたはマクロを 定義する必要があります。 注:古いバージョンでは、':'を修飾語として使用していました。残念ながら、 既存のコード(SLIBなど)では擬似的な修飾子として ':' が使われており、本当の 修飾子としての使用は基本的に不可能です。