REBOL
REBOL は、データ交換言語であり、通信や分散処理に特化したプログラミング言語である。Relative Expression Based Object Language の略。設計者カール・サセンラスはこれをメッセージング言語と呼び、「REBOL の主なアイデアは、サーバ、クライアント、その間の通信やそれらのストレージで使える言語にするというものであった。REBOLの能力は、プログラミング言語の概念とメタデータ言語の概念を統合したことに由来する。REBOLの究極の目的は、インターネット上のあらゆる機器間で情報がどのように格納され、交換され、処理されるかを表す新たなアーキテクチャを提供することである。すなわち、人間と機械の間の情報の意味論的交換に使われることを意味する」と述べている。
1997年にリリースされたREBOLは、カール・サセンラスが20年に渡って設計したものである。サセンラスは AmigaOS の主要アーキテクトであり、REBOLの設計にあたっては、表示的意味論の知識に基づいて、LISP、Forth、LOGO、Self といったプログラミング言語の概念を利用した。
REBOO/Command は2000年9月にリリースされ、暗号化機能、ODBCアクセスなどが追加されている。REBOL/View は2001年4月にリリースされ、グラフィックス機能が追加されている。2001年8月にリリースされた REBOL/IOS は、拡張可能な共同作業環境である。2002年12月には、ソフトウェア開発キットがリリースされた。
2012年9月、R3(REBOL 3)オープンソースとして公開されることが発表される。2012年12月には、安定版がリリースされた。ライセンスはApache License 2.0。
REBOL はインタプリタ型高級言語であり、マルチプラットフォームでマルチパラダイムであり、動的リフレクションをサポートした言語である。同図像性(Homoiconicity)があり、コードとデータが同じ形式で表現され、メタプログラミングに最適である。
構造化プログラミング、関数型プログラミング、プロトタイプベースプログラミングをサポートしている。REBOLは純粋関数型言語ではなく、副作用のある命令型プログラミングの要素もある。また、純粋オブジェクト指向言語でもなく、オブジェクトでないデータ型も持っていて、他のプログラミングパラダイムもサポートしている。REBOLは特に言語指向プログラミングに適しており、さらに言えばダイアレクティング(方言派生)に適している。
REBOLは動的プログラミング言語であり、動的型付け(値は強い型付けだが、変数はそうではない)である。メモリ管理にはガベージコレクションを使い、例外処理と動的名前解決をサポートしている。
データ交換言語としての利用を可能とするため、REBOLには以下のような最小限の構文がある。
文の概念はない。構文の基本単位は式である。
キーワードは存在しない。
空白と [, ], (, ), ", {, } を区切り記号として用いる。
数々のデータ型が備わっていて、その多くは字句形式(後述)で定義されている。
データ言語としてのREBOLは強く型付けされた値を持つ。30以上のデータ型が元から備わっている。多くの他の言語と同様、整数、10進数、文字列といった基本的な値がある。REBOLではさらに字句形式で識別されるデータ型があり、例えば、電子メールアドレス型 (name@host.dom)、URL型 (http://www.rebol.com)、マークアップタグ型 (<b>, <font size="2" color="blue">)、価格型 ($100.00, USD$25.25)、日付型 (30-Nov-2005, 1-Dec-2005/10:30-7:00)、時刻型 (12:00:00)、座標対型 (5x5)、タプル型 (255.255.255, 192.168.100.1)、単語列型 (how are you?) などがある。これらのデータ型はプログラマ以外にもわかりやすい字句形式を使っていて、それによってデータ交換言語として使えるようになっている。REBOLにおいて値をグループ化するのに使われる主なデータ構造を「ブロック」と呼び、これはLISPの「リスト」にある意味で似ている。
REBOLインタプリタにはいくつかのエディションがある(/Core、/View、/Command、/Base、/Face、/Pro)。本稿執筆時点では、/Core が /Base 以外の他のエディションのサブセットになっていて、43 のプラットフォームで利用可能になっている。
REBOLインタプリタのソースコードは非公開である。REBOL/Core と REBOL/View で開発したアプリケーションは有償配布しても課金されない。REBOL/Pro などの拡張エディションではライセンス料の支払いが必要である。これにはODBCアクセス、ダイナミックリンクライブラリの利用、スタンドアロンのEXEファイル生成といった機能がある。
ランタイム環境は、現状では単一の実行ファイルとなっている。REBOL/Core では約300kB、REBOL/View(GUIエディション)は約650kBである。アプリケーションのスクリプトは数キロバイトを超えることは少ないため、インタプリタ本体とスクリプトを一枚のフロッピーディスクに格納できるし、電子メールでスクリプトを送るのも容易で、インターネット上で転送して実行することもできる。
インターネット上の各種プロトコルをサポートしており、電子メールエージェント、Webアプリケーションといったインターネット・アプリケーションも容易に書ける。
REBOL/View はプラットフォーム独立なグラフィック/サウンド・アクセスを提供しており、独自のウィンドウツールキットと拡張可能なウィジェット群を持つ。これにより、分散GUIアプリケーションが容易に構築できる。REBOLのダイアレクティング・モデルにより、軽量な分散コンピューティングアプリケーションの開発もできる。
REBOLコミュニティは、"REBOL desktop" を通してリンクしている。REBOL desktop はインターネット上のREBOL関連ファイルをグラフィカルに表現したもので、REBOLインタプリタに付随してインストールされる。REBOL desktop 自体はオープンソースのREBOLアプリケーションである。
コンソールに Hello world と表示するだけなら、次のように打ち込めばよい。
クロスプラットフォームのGUI版では、次のようになる。
さらに、HTTP と SMTP を使った単純なインターネットアプリケーションの例を示す。
REBOL という単語で始まるヘッダ部は、インタプリタがスクリプトの開始を知るために必要とされる。ヘッダは単に REBOL [] でもよいのだが、一般に例にあるような説明的記述をするのがよいとされている。
REBOLはコンテンツ依存言語であり、ダイアレクト(dialect)と呼ばれるドメイン固有サブ言語をサポートしている。例えば、return という単語の解釈がコンテンツによって変わることを見てみよう。通常、return は関数を完了して呼び出し元に値を返すのに使われる。しかし、Visual Interface Dialect (VID) では、return という単語があるとレイアウトエンジンが改行(carriage return)と解釈し、レンダリングペンを次行の先頭に持っていく。REBOLプログラマは独自のダイアレクトを生成でき、既存のREBOLの単語に別の意味を付与することができる。
ダイアレクトは、REBOLブロックを特定の方法で処理する関数で実装されるのが一般的である(後述の例のように文字列処理での実装もある)。同様に他の関数でも、ネイティブのダイアレクトとREBOLで書かれたダイアレクトを識別可能である。
ダイアレクトの例:
do ダイアレクト - REBOLの通常の do 関数が理解し解釈できる(ネイティブ)。
reduce ダイアレクト - doダイアレクトで結果を集めるよう変更したもの(ネイティブ)
compose ダイアレクト - reduceダイアレクトで括弧だけを評価するよう変更したもの(ネイティブ)
function spec ダイアレクト - 関数ヘッダ記述に使われるダイアレクト(ネイティブ)
parse ダイアレクト - バッカス・ナウア記法風の文法規則を記述するためのツール(ネイティブ)
VID - GUI用ダイアレクトで、layout関数として実装されている(mezzanine)。
ユーザーは任意のREBOL関数を使ってダイアレクトを生成できるが、reduce 関数と compose 関数がよく使われており、parse 関数はダイアレクト生成に最適化されている。
parse関数の目的は、BNF風の形式のParsing Expression Grammarの構文規則を指定することでダイアレクトの解釈を与えることであり、yaccやBisonのような構文解析ツールに似ている。REBOLは実行時にそういった規則を解釈する。構文解析中に実行すべきことも指定できる。
parse関数は、REBOLブロックまたはREBOL文字列を処理するのに使われる。
parseによる文字列処理は非常に柔軟性があるが、低レベルな手法であるため、手間がかかる。ブロック解析のほうが簡単だが、制限がある。ブロック解析では、ROBOLは書かれている規則をREBOLの値の並びとして字句解析する(文字列解析では文字と区切り文字として解釈する)。そのため、より抽象化された規則として記述できるが、通常のREBOLの字句形式にマッチしていなければならない。
parse 関数に解釈させる規則群自体も REBOL のダイアレクトで書く。文字列として解析する場合、REBOLのデータ型の一部を規則に使用できる。ブロックとして解析する場合、全てのREBOLデータ型が使え、他にもダイアレクト構築を容易にする機能が使える。
最初の例は、文字列を解析して特定の単語を探し、関連するデータの一部を変数としてコピーし、他の場所でそれを使う。この例では、文字列からコピーされた部分も文字列である。具体的に言えば、"write" または "send" で始まる命令文型の文字列を入力として、簡単な構文解析で「何を」「誰が」「どうする」のかを把握する処理が記述されている。
"parse string" ブロックの最後の行を見てみると、"copy what" は現在パーサが見ている位置("a" または "the" の後)からのテキストをコピーすることを意味し、それを変数 "what" に代入する。また、ダイアレクトは "to end" を指定しているので、文字列の最後尾まで全てをコピーすることを意味する。従って "what" には第一の文字列なら "thank-you note"、第二の文字列なら "new source code" が代入される。
と打ち込むと、以下のように出力される:
What: thank-you note
What: new source code
ファイル解析ユーティリティがあり、ユーザーが操作すべきファイルを指定し、それをいつ実行し、結果をどこに送り、誰に通知するかということを簡単に指定できるようにしたいとする。ダイアレクトは、この種のタスクに対して、柔軟なテキストベースのインタフェースを提供できる。
ダイアレクトは複数のアイテムを許容し、語順が変動しても問題なく、可読性のために人間が余分な単語を追加してもプログラムの動作には影響を与えない。
ここでは、ユーザーがアプリケーションに送るコマンドセットを2種類定義している。
この例で、file、email、time、url といったものは全てREBOLにおけるネイティブなデータ型であり、構文解析中にそれらの値を抽出して、直接 REBOL の式に適用可能である。例えば、 who の値は send 関数で電子メール送信に使われ、target の値は write 関数によるデータのポストに使われる。