1.1 起源と開発

Schemeは、1970年代にマサチューセッツ工科大学MIT)の人工知能研究所で、ガイ・L・スティール・ジュニアとジェラルド・ジェイ・サスマンによって開発されたLisp方言である。当初は、構造化プログラミングと教育的な目的のために設計され、従来のLispが持つ動的スコープを静的スコープに置き換えるなど、言語理論の新しい概念を実験する場として機能した。最初の実装は1975年に発表され、「Scheme」という名称は、制御フローのための「scheme」(計画)という概念に由来する。

1.2 標準化の経緯(RnRS)

Schemeの標準化は、Revised^ Report on the Algorithmic Language Scheme(略称RnRS)という一連の文書によって行われた。最初の改訂版(R0RS)は1978年、続くR1RS(1984年)、R2RS(1985年)、R3RS(1986年)を経て、R4RS(1990年)で広く普及した。その後、R5RS(1998年)が長らく事実上の標準となり、R6RS(2007年)では大規模な改訂が行われたが、コミュニティの分裂を招いた。最新の標準はR7RS(2013年)であり、小型実装向けのR7RS-smallと大規模システム向けのR7RS-largeに分かれている。

2.1 構文と記法

2.1.1 S式とリスト

Schemeの構文はS式(Symbolic Expression)に基づく。S式はアトム(数値、シンボル、文字列など)か、括弧で囲まれたリスト(例: (a b c))で構成される。プログラム自体もS式として表現され、リストの最初の要素は手続きや特殊形式を指定する演算子となる。この統一された表現により、コードとデータの区別が曖昧になり、強力なメタプログラミングを可能にする。

2.1.2 評価モデル

Schemeの評価は、インタプリタ型のモデルに従う。式は左端から順に評価され、リストの最初の要素が手続きであれば、残りの要素が引数として評価された後に適用される。シンボルは変数名として解決され、その束縛された値が返される。特殊形式(defineiflambdaなど)は独自の評価規則を持ち、引数を条件付きで評価する。

2.2 データ型とリテラル

2.2.1 基本データ型

Schemeは動的型付けであり、実行時に型が決定される。基本データ型には、整数(例: 42)、浮動小数点数(例: 3.14)、真理値#t#f)、文字(#\a)、文字列("hello")、シンボル('foo)、手続き、および空リスト('())が含まれる。数値は任意精度をサポートし、分数や複素数も扱える。

2.2.2 複合データ型

複合データ型として、リスト、ベクター、連想リスト(association list)などがある。リストは'(a b c)のように記述され、conscarcdrなどの基本操作でアクセスする。ベクターは#(1 2 3)と表記され、固定長のシーケンスであり、vector-refでインデックスアクセスできる。また、構造体やレコードはR6RS以降で標準化された。

2.3 手続きと関数

2.3.1 ラムダ式

Schemeでは、手続き(関数)は第一級オブジェクトであり、lambda式を用いて無名関数を作成できる。(lambda (x) (* x x))は引数xを受け取りその二乗を返す手続きを生成する。defineを用いて名前を付けることも可能であり、(define square (lambda (x) (* x x)))と書ける。ラムダ式はクロージャとして機能し、定義時の環境を保持する。

2.3.2 高階関数

手続きを引数として受け取ったり、戻り値として返す関数は高階関数と呼ばれる。Schemeは基本的な高階関数としてmapfilterfold畳み込み)などを提供する。例えば、(map square '(1 2 3))(1 4 9)を返す。高階関数を利用することで、再帰的な処理を抽象化し、コードの再利用性を高めることができる。

3.1 条件分岐

条件分岐にはifcondが主に用いられる。if(if 条件 真式 偽式)の形式で、条件が真(#t以外の値)なら真式を、偽(#f)なら偽式を評価する。condは多分岐に適しており、(cond (条件1 式1) (条件2 式2) (else 式3))のように記述する。また、whenunlessといったマクロもよく使われる(R7RSで標準化)。

3.2 反復再帰

Schemeは伝統的に繰り返しにdoや名前付きletを提供するが、最も自然な反復方法は再帰である。リストの処理は再帰で記述され、(define (length lst) (if (null? lst) 0 (+ 1 (length (cdr lst)))))のように書ける。

3.2.1 末尾再帰の最適化

Schemeは末尾再帰の最適化(TRO)を必須とする。手続きの戻り値としての再帰呼び出しが末尾位置にある場合、スタックフレームを消費せずにループとして実行される。これにより、(define (fact n acc) (if (= n 0) acc (fact (- n 1) (* n acc))))のような再帰は、スタックオーバーフローを起こさずに任意のnに対して動作する。

3.3 継続とコルーチン

Schemeは制御の継続(continuation)を第一級オブジェクトとして扱う。call-with-current-continuation(通称call/cc)は、現在の継続を手続きとして取り出し、任意の時点で呼び出すことでプログラムの実行状態を復元できる。これにより、例外処理、コルーチン、バックトラッキングなどを実現できる。

3.3.1 call/ccの応用

call/ccは、非同期処理や協調的マルチタスクの実装に利用される。例えば、コルーチンはcall/ccを用いて、実行中の関数の継続を保存し、後で再開する。また、大域的脱出(非局所脱出)としても使われ、深いネストからの一括脱出を簡潔に記述できる。ただし、理解が難しいため、実用的には継続限定の演算子(shift/resetなど)が好まれることもある。

4.1 マクロシステム

Schemeのマクロシステムは、構文抽象化を提供し、プログラムのコードを別のコードに変換する。R5RSまでの伝統的なマクロはdefine-macroのような手続きによる定義だったが、R6RS以降では衛生マクロ(hygienic macro)が標準化された。syntax-rulesは簡単なパターンベースのマクロを定義でき、syntax-caseはより柔軟な変換が可能である。マクロはコンパイル時に展開され、新しい構文構造を導入できる。

4.2 モジュールとライブラリ

R5RSではモジュールシステムは規定されていなかったが、R6RSとR7RSで標準化が進められた。R7RS-smallではdefine-libraryimport/exportを用いたライブラリ機構が導入され、コードの分割と名前空間の管理が可能になった。各処理系は独自の拡張モジュールシステムを提供することも多く、例えばRacketは高度なモジュールシステムとパッケージ管理を備える。

4.3 入出力と副作用

Schemeの入出力は、ポート(port)を通じて行われる。標準入力、標準出力、標準エラー出力へのアクセスには、それぞれcurrent-input-portcurrent-output-portcurrent-error-portを用いる。ファイル操作はopen-input-filecall-with-input-fileで行い、副作用を持つ手続きとしてはdisplaynewlinewriteなどがある。R7RSではバイナリ入出力や文字符号化のサポートも強化された。

5.1 処理系一覧

5.1.1 Gambit

Gambitは、高速なコンパイル方式を採用したScheme処理系であり、C言語へのトランスレータとしても動作する。Gambitは軽量なスレッド(協調的マルチタスク)を内蔵し、並列計算にも対応している。また、Cとの連携が容易であり、組み込み用途やパフォーマンス重視のアプリケーションで利用される。

5.1.2 Chicken

Chickenは、SchemeコードをC言語に変換してコンパイルする処理系である。生成されたCコードはPOSIX環境で動作し、拡張ライブラリ(egg)と呼ばれる豊富なパッケージが提供される。ChickenはR5RSに準拠しつつ、R7RSの一部機能もサポートし、実用的なソフトウェア開発に適している。

5.1.3 Racket(旧PLT Scheme)

Racketは、PLT Schemeから発展したマルチパラダイム言語処理系であり、強力な言語指向プログラミング(言語オークストレーション)を特徴とする。独自のIDE(DrRacket)や豊富なライブラリ、型推論を備え、教育からプロトタイピングまで幅広く使われる。スケーラブルな文法拡張機能により、Schemeのサブ言語以外にも多くの言語を定義できる。

5.2 ツールと開発環境

Schemeの開発環境は多岐にわたる。テキストエディタとしてはEmacs(geiserモード)やVim(slimv/vim-racket)が一般的であり、REPL(Read-Eval-Print Loop)を用いた対話的開発が主流である。Racketには独自のIDE(DrRacket)が付属し、デバッグやプロファイリング機能も統合されている。また、ユニットテストフレームワーク(SRFI 64)やドキュメント生成ツール(Scribble)など、生産性を高めるツールが多数存在する。

6.1 教育での利用

Schemeは、コンピュータサイエンス教育において広く用いられてきた。特に、MITの教科書『Structure and Interpretation of Computer Programs』(SICP)は、Schemeを基盤として計算プロセスの抽象化、再帰、データ構造、メタ抽象化などの概念を教える。その最小限の文法により、言語の詳細ではなくプログラミングの本質に集中できる点が評価されている。近年ではRacketも教育的なプラットフォームとしてよく使われる。

6.2 研究分野での影響

Schemeはプログラミング言語理論の研究において重要な役割を果たしてきた。静的スコープ、第一級継続、衛生マクロなどの概念は、Schemeを通じて広まり、他言語(JavaScript、Python、Rubyなど)に影響を与えた。また、型システムやプログラム検証の実験台としても利用され、多くの論文でSchemeが実装言語として採用されている。関数型プログラミングや遅延評価の研究にも貢献した。

6.3 ユーモアと文化(例:Schemeコードゴルフ)

Schemeコミュニティは、言語の簡潔さと表現力を活かした遊び心ある文化を持つ。コードゴルフ(最短コードコンテスト)はその一例であり、Schemeの強力な抽象化と再帰を駆使して、短く読みにくいコードを競う。また、FOOM(関数型オブジェクト指向ミニマリズム)やamb(非決定性)演算子を用いたパズルも人気がある。インターネット上では、#schemeタグやSICPに関するジョークが共有されるなど、軽妙な雰囲気が保たれている。