June 2017

Volume 32 Number 6

C# - Hyperlambda を使って C# をより動的にする

Thomas Hansen

プログラミング言語には、昔から、静的なコンパイル言語と動的なインタープリター言語の 2 種類しかありません。実際には、3 種類目のプログラミング言語があり、どちらのカテゴリーにも属さず、他のすべての言語に比べて非常に厳格だとしたらどうでしょう。

そのような言語が Hyperlambda です。これは、Active Events 全体を土台にしてビルドされたチューリング完全な実行環境です(前回のコラム msdn.com/magazine/mt795187 を参照してください)。Hyperlambda は、インタープリター言語でもコンパイル言語でもありません。構文さえありません。Hyperlambda は非プログラミング言語です。反プログラミング言語とさえいえるかもしれません。技術的には、まったくプログラミング言語ではありません。基本的には、Hyperlambda は、ツリー構造を宣言できるようにする、リレーショナル ファイル形式にすぎません。おそらく、C# や JavaScript よりも、HTML や XML と共通する部分が多いといえます。それでも、このツリー構造を使えば、一般に実行ツリーと呼ばれるものを記述できます。

実行ツリーとは、CPU が実際に実行するものです。すべてのプログラミング命令は基本的にはツリーの分岐と考えられ、CPU はコードを評価しながらそのツリーを辿って移動します。たとえば、if/else ブロックは相互排他的に実行できる 2 つの分岐を作成し、if ステートメントの条件に応じて CPU が 1 つの分岐だけを選択します。本質的には、コードの実行時にコンピューターが行うことは、実行ツリーを辿って移動しながら、処理中にメモリを操作することです。つまり、実行ツリーを記述してメモリを操作できれば、これまで C# や JavaScript を使って記述してきたものを記述できることになります。

すべてはツリー

Lisp では「リスト」がすべてであるのと同様に、Hyperlambda では「ツリー」がすべてです。解析後に実行ツリーを作成する Hyperlambda を疑似コードにすると、以下のようになります。

if:condition
  do-x:argument1
else
  do-y:argument1

このコードを解析した結果が、ラムダ オブジェクトです。このラムダ オブジェクト (実行ツリー) は、Phosphorus Five (P5) の Active Event の eval を呼び出すことで評価できます。基本的に、Active Event は「関数オブジェクト」と考えることができます。つまり、唯一の引数としてのグラフ オブジェクトまたはツリー オブジェクトを指定して、たとえば C# で記述したメソッドを呼び出すことができます。P5 は、設計パターン「Active Event」を実装します。

このようなラムダ オブジェクトを作成したら、P5 の Active Event の eval が、ルート ノードの子ノードを順番に最初から最後まで Active Event として呼び出します。先ほどの例で作成したラムダ オブジェクトには 4 つのノードがあり、そのうち 2 つがルート ノードです。したがって、eval は "else" を実行する前に、"if" を実行することになります。

そのため、ラムダ オブジェクトは、Hyperlambda が作成する「DOM 構造」です。希望するなら、Hyperlambda ではなく、XML を使用してもこのようなツリー構造を記述することはできます。ただ、このようなツリー構造を記述する場合、Hyperlambda の方が優れた手法だっただけです。Hyperlambda を HTML や XML と考え、結果として作成されるのが DOM 構造だと考えると、わかりやすくなるかもしれません。

Hyperlambda の構文は極めてシンプルです。すべてのノードは、名前、値、子ノードを持つことができます。主な制御構造は以下がすべてです。

  • ノードの名前と値はコロンで区切る。
  • 子ノードのコレクションは 2 つのスペースで始まる。

オプションでノードの値の型宣言が可能です。型宣言は、名前と値の間に挟む形で行います。しかし、型宣言はオプションで、めったに使用しません。Hyperlambda の既定の型宣言は文字列です。

Hyperlambda の特徴

C++ や C# などの静的言語は、コードをコンピューターが実行できる機械語にコンパイルしてから、その結果の実行を開始します。JavaScript などの動的言語は、通常、その場でコードを翻訳しながら、そのコードを実行します。Hyperlambda はこのどちらにも当てはまりません。代わりに、実行ツリーを宣言します。このツリーが P5 によって解析され、その結果、P5 の Active Event の eval を使用して評価されるラムダ オブジェクトが生成されます。ラムダ オブジェクトを作成する構文を考えることすらありません。ラムダ オブジェクトを宣言するには、リレーショナル ツリー構造を宣言できる任意のファイル形式を使用できます。つまり、Hyperlambda は HTML や XML と同程度のプログラミング言語にすぎません。ただし、チューリング完全な実行環境であることに変わりはないため、他のプログラミング言語でできることはすべて行うことができます。おそらく、ラムダ オブジェクトの宣言に HTML を使用していたとしたら、その時点で HTML はチューリング完全なプログラミング言語になっていたでしょう。

ツリーの分岐

Hyperlambda のすべてのキーワードは、1 つの Active Event にすぎません。これらの Active Event を呼び出すと、ある種の条件に応じて、eval を再帰的に呼び出すことになります。そのため、Hyperlambda の拡張性は極めて高くなります。新しいキーワードの作成は、5 行のコードを作成するだけのことです。C# での例は次のとおりです。

[ActiveEvent (Name = "what-is-the-meaning-of-life?")]
private static void foo (ApplicationContext context, ActiveEventArgs e)
{
  e.Args.Value = 42;
}

実際には、if と else の両方のキーワードはこのような Active Event として作成されています。

C# を使用して Active Event やキーワードを作成する必要はありません。Hyperlambda では独自のキーワードを作成することもできます。

create-event:what-is-the-meaning-of-life?
  return:int:42

Hyperlambda は間違いなく非常に高いレベルの抽象化です。しかし、なんらかの哲学的レベルからすれば、非常に低レベルの抽象化であり、既存の他のプログラミング言語よりもはるかに低いレベルであるとも考えられます。というのも、修正の対象がコードではなく、実際には実行ツリーになるためです。観察眼に優れた読者であれば、すでにお分かりのことだったかもしれません。DOM モデルに HTML や XML にとって多くのメリットがあるるように、Hyperlambda のこの特性にも多くのメリットがあります。まず、コードは極めて柔軟で、自己修正可能です。つまり、通常、コードの作成とコードの実行を分けて考える必要はほとんどなく、コードの作成と実行の両方を少しずつ行うことができます。いくつかの入力データを受け取るラムダ オブジェクトを評価することで、実行ツリーに新たなロジックと追加の分岐を簡単に作成できます。たとえば、なんらかの理由で特定の if/else ブロックが好ましくない場合、それを含むラムダ オブジェクトの評価を開始した後であっても、動的にそのブロックを削除できます。実際、実行ツリーは、ラムダ オブジェクトに提供する入力データによって、まったく異なるものになることもあります。

DOM モデルを使って JavaScript で HTML ページの一部を修正できるように、実行中に「ラムダ オブジェクト モデル」を使用してラムダ オブジェクトの一部を変更できます。文字通り、実行ツリーは、実行中に変更できる動的エンティティになります。

Hyperlambda ファイル形式とラムダ オブジェクトの相互変換は、Active Event を呼び出す程度の簡単な操作です。Hyperlambda ファイル形式は、シリアル化可能で本質的に永続的なもので、ラムダ オブジェクトは実行ツリーです。

分岐の検索

Hyperlambda 固有の性質の 1 つは、変数がないことです。すべてのものが変更不可だという F# と同じ意味で変数がないということではありません。文字どおりの意味で、Hyperlambda には変数がありません。 この点では、疑問があって当然です。結局のところ、実行ツリーとメモリの状態を変更できることは、チューリング完全な実行ツリーを作成するうえで重要なことです。ただし、実行ツリーの状態を変更できるのであれば、これまで変数と呼ばれてきたものは実際のところ必要ありません。

Hyperlambda では、あらゆるものを変更できます。Hyperlambda で何かを変更することは、変更するノードを参照し、変更操作のソースを提供することにすぎません。そのため、まず必要なのは、ツリー内のノードを参照する方法です。これは、以下のようにラムダ式で行います。

_data:Thomas
if:x:/@_data?value
  =:Thomas
  say-hello:Yo boss
else
  say-hello:Yo stranger

このコードは 1 つのラムダ式を示しています。このラムダ式では、_data ノードの値を参照し、Active Event の if の呼び出しの引数としてこの値を指定しています。この if の呼び出しでは、静的な値 "Thomas" とラムダ式の結果を比較し、"_data" の値が "Thomas" と等しい場合は、if ノード内のラムダ オブジェクトが評価されます。等しくない場合は、else ノードのラムダ オブジェクトが評価されます。

ラムダ式ではツリー内の任意のノードを参照できます。その結果は、元のツリーを基にするサブツリーになります。ラムダ式とツリー構造の関係は、SQL とテーブルの関係と似ている部分があります。ラムダ式は、XPath の式を作成した経験があれば簡単に想像できます。ラムダ式を LINQ や "事前コンパイル済みの列挙子" と比較してもかまいません。後者は、ラムダ式が実際に実装される方法です。LINQ クエリを組み立てることは動的に値を追加することだと考えるなら、まったく論理的にラムダ式は値を所有できると考える必要があります。

ツリーの切り取り

この時点で、チューリング完全な実行環境にするために必要なのは、ツリーの一部を変更可能にすることだけです。こでは Active Event の "set" を使ってこれを行います。

_input:Thomas
_output
if:x:/@_input?value
  =:Thomas
  set:x:/@_output?value
    src:Yo boss
else
  set:x:/@_output?value
    src:Yo stranger

Active Event の set は、基本的には C# の代入演算子のように機能します。これで、チューリング完全な "非プログラミング言語" を用意できたことになります。この言語では、これまでのプログラミング言語で行ってきたすべてのことが行えます。実際にプログラミング言語を作成することも、構文を考えることも必要ありません。代わりに、ラムダ オブジェクトの評価に応じて実行ツリーを直接変更します。

ツリーの変更に使用できる Active Event は他にもあります。たとえば、"add" はラムダ式の結果にノードの分岐を付加します。これによって、1 つ以上のノードが追加されます。一方、"insert-­before" と "insert-after" も同じようにノードを追加しますが、ノードの分岐の前または後に 1 つ以上のノードを挿入します。ノード、値、または名前の削除は簡単で、設定先のソースを指定しないだけです。つまり、式に使用する型宣言に応じて、ノード、ノードの値、またはノードの名前が単純に削除されます。

このような構成を使用することで、実行ツリーを直接変更可能にするために必要なツールをプログラマにもたらし、C# を極めて動的なプログラミング言語にします。おそらく、Hyperlambda のこのような特性によって、地球上で間違いなく最も動的なプログラミング環境になります。Lisp や JavaScript などの非常に動的な言語でさえ、Hyperlambda と比べてしまえば、絶望的なほどに静的で厳格性が高いように思えてしまいます。

この時点で、Hyperlambda にはデータとロジックに絶対的な違いはありません。ロジックがデータであり、この 2 つの意味の違いはまったくないことがわかります。つまり、データと同じようにロジックを簡単に変更でき、実行中に実行ツリーを完全に変更できる極めて動的な実行モデルになります。これがどれほど優れているかを、非常に役立ついくつかのユース ケースを使って説明します。

ツリーの育成

ユース ケース 1: データベースに 100 件のレコードがあるとします。各レコードにはなんらかの Hyperlambda も含みます。希望すれば、これらのレコードをすべて選択し、ラムダ オブジェクトに変換して、それを目的のラムダ オブジェクトに付加できます。その後、組み合わせた結果を評価します。これらのレコードから 1 つの関数オブジェクトを新たに作成し、ディスク上のファイルに保存して、関数を呼び出すのと同じ方法でこのファイルを使用することもできます。

ユース ケース 2: 希望すれば、関数の半分だけを評価し、実行しない関数部分を削除できます。この機能があるプログラミング言語は地球上には他に存在しないと思います。これは極めて有用な機能です。

ユース ケース 3: 必要に応じて、5 つの異なる関数から半分のラムダ オブジェクトを抽出し、元の関数の「適切な部分」から派生した新たな関数を 1 つ作成できます。

なぜこのようなことが可能なのでしょう。 1 つのラムダ オブジェクトは、XSLT ファイルが XML ファイルを変換できるのと同じように、他の任意のラムダ オブジェクトを変換することができます。システム内の while ループを実行しない場合、いくつかの理由から、すべての while ループを変換して for-each ループに変えるラムダ オブジェクトを簡単に作成し、自動プロセスとしてバックグラウンドで実行することができます。

よくわからない場合は、DOM モデルとの関係で HTML のしくみを考えます。DOM では JavaScript を使って HTML 要素の挿入、修正、削除を行います。Hyperlambda でのラムダ オブジェクトの変更はこの程度の容易さです。JavaScript の機能が HTML に価値を追加すると考えるのなら、まったく論理的に「ロジック」に価値を追加できる可能性があることは間違いありません。 Hyperlambda は、ソフトウェア開発に関して、まったく新たな次元を切り開きます。

ユース ケース 4: System42 の CMS を考えます (bit.ly/2pwMOY9)。この CMS によって、単に静的な HTML を表示するのではなく、100% 動的で本質的にインタラクティブなラムダ ページを作成できるようになります。PHP は少なくとも理論上同じことができる「すばらしいもの」だと論じられることがあります。ただし、このようなラムダ ページは、再利用可能なコンポーネントでもあります。たとえば、Hyperlambda の動的な性質によって、ラムダ ページの実行中に "parent-widget" 引数の存在をチェックできます。この引数が存在する場合は、ページを作成する代わりに、同じページをユーザー コントロールとしてページ上の別のウィジェットに挿入できます。

実際には、元のページを変更する必要もなく、代わりに "create-widget" の呼び出しを評価する前にラムダ オブジェクトを変換できます。これまでのプログラミング言語で行われてきたように、ものごとを絶対的なものとして分類することは、Hyperlambda ではまったく無意味です。

結果として、Hyperlambda で作成するすべての単一ラムダ オブジェクトは、システムの他の部分に挿入できる再利用可能なコンポーネントになる可能性があります。つまり、以前に作成したシステムを土台に、徐々に複雑さを増すシステムを段階的に作成できます。従来のプログラミング言語では、システムをビルドするか、再利用可能なコンポーネントをビルドするかを選択する必要がありました。Hyperlambda では、そのような相互排他的な選択は意味がなく、多くの場合、すべてのものが他のものの一部分になる可能性があります。Hyperlambda の再利用可能という特徴により、プログラミング人生でこれまで経験してきたすべてのものがまったく大したことのないものになります。

ユース ケース 5: Hyperlambda では、引数を実行に渡して、ディスク上のフォルダーを実際に再帰的に実行し、これまでのプログラミングの制約をすべて取り除きます。つまり、関数を呼び出すようにファイルを呼び出し、このファイルの呼び出しから複数の値を呼び出し側に返すことができます。また、サーバーに転送された HTTP POST リクエストの本文を簡単に呼び出して、これまで作成していた 1 つの Web サービス エンドポイントをそれぞれ 5 ~ 15 行のコードに効率よく置き換えることも可能です。これらすべては、Hyperlambda を使用してほぼ毎日のように行うことです。

ユース ケース 6: Hyperlambda では、Web ページを純粋な Web ページとして考えることさえ無意味になります。それは、アプリケーション プール内の 1 つのアセンブリを置き換えるだけで、まったく同じコードを使って Windows フォームのアプリケーションを簡単に作成できるためです。Hyperlambda では、Web アプリケーションや Windows Forms アプリケーションに、実際驚くほど簡単に同じコード ベースを再利用できます。コードの GUI 部分でさえ再利用可能です。

Hyperlambda を他の開発者に示すと、この点が見過ごされがちです。それは、Hyperlambda がこれまでのプログラミング言語よりもはるかに冗長に見えるためです。たとえば、前述のコード例では、C# を使えば 1 行で簡単に記述できたものが、Hyperlambda では 9 行必要です。簡単なタスクの場合、Hyperlambda は冗長になる場合があるのは明らかです。しかし、Hyperlambda には、この問題を緩和する特徴が 1 つあります。それは、ラムダ オブジェクトを変換する機能です。これにより、長期的に見ると、コードの冗長性は大幅に少なくなります。そのため、基本的に、初めは少し負担になります。短期的には、比較的冗長なコードになりますが、長い目で見れば、極めて簡潔なコードへと変わります。その結果、はるかに少ない作業量で、極めて高い機能を提供できるようになります。Hyperlambda によって、ソフトウェアの生産性が飛躍的に高まります。このことを少しじっくりと考えてみてください。

Hyperlambda の Hello World

以下は、Hyperlambda で作成した "Hello World" アプリケーションです。このコードをたとえば System42 CMS のラムダ ページなに貼り付けると、クリック時にボタンの値が「I was clicked (クリックされました)」となるように変化するボタンが作成されます。 P5 をダウンロードし、この Apps/CMS アプリケーションを開始して実際に試してみます。その後、ラムダ ページを作成して、以下のコードに貼り付けます。

create-widget:foo-widget
  element:button
  class:btn btn-default
  innerValue:Click me!
  onclick
    set-widget-property:foo-widget
      innerValue:I was clicked

同様のものを作成するとき、使用しているフレームワーク、ライブラリ、言語の種類に応じて、JavaScript、C#、HTML のコードは数百行になる可能性がありますが、Hyperlambda ではこの 7 行のコードに置き換わります。慎重にコードを読んでみると、生成される HTML マークアップを想像できると思います。Hyperlambda は多くの場合に他のプログラミング言語よりも自然言語に近くなります。言語学的には、C# や JavaScript などよりも人間どうしの普段の情報伝達の形に似ています。

その他の利点として、独自の Windows Forms アセンブリを作成する場合、前述の Active Event の create-widget の代替実装を使用して、まったく同じコードで Windows Forms アプリケーションを作成できます。

Hyperlambda は特効薬か

これまで Active Event を推奨してきましたが、特効薬の宣伝だと非難を浴びました。これまでの発言が、おそらく魔法のように聞こえることもあるというのは認めます。もちろん、Hyperlambda は内部の実装セマンティクスによって、プログラミング命令の実行に余分なオーバヘッドが生じるだけでなく、初めは冗長なコードを作成することになります。また、時折バグを発見することもあり、リファクタリングすることで、さいわいにも適切なコードになることもあります。Hyperlambda が完璧ではないことは明らかです。

しかし、Hyperlambda の最大の問題は、実際には開発者の頭の中にあります。Hyperlambda は、ソフトウェア開発のベスト プラクティスとしてこれまで 50 年間教えられてきたすべてのことを完全に無効にします。それが実際に証明されている Hyperlambda の特徴です。

ただし、結局のところ、Hyperlambda は特効薬かという問いに対する答えは 1 つではありません。それは開発者自身が判断することです。Hyperlambda で全体的にビルドされ、GMail のクローンである Sephia Five の例を確認することをお勧めします (github.com/polterguy/sephia-five)。Sephia Five は PGP 暗号化機能とウィルスやマルウェアから 100% 完璧に保護する機能を備えています。これは、HTML を表示できるすべてのデバイスで機能します。また、Sephia Five は、GMail よりも桁違いに効率的に帯域幅を使用します。最初のリリースは、何もないところから文字どおり 5 日間でビルドしました。これらすべての説明は、確認および検証でき、数学的に再現および証明できます。

Hyperlambda に関する詳細については、github.com/polterguy/phosphorusfive-dox のガイドを参照してください。また、github.com/polterguy/phosphorusfive の Phosphorus Five と共に Hyperlambda をダウンロードできます。


Thomas Hansen は、1982 年に Oric-1 コンピューターを使用してコードを記述し始めた 8 歳の頃から、ソフトウェアを作成してきました。たまに、デメリットよりもメリットが上回るコードを作成しています。彼は、Web、AJAX、アジャイルの方法論やソフトウェア アーキテクチャに情熱を傾けています。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの James McCaffrey に心より感謝いたします。