はじめに

KL(ケーゥと発音します)とは、 Fabric Engine のオペレータに使用されるプログラム言語です。KLは「カーネル言語」の意味します; この文脈では、 kernel とはマルチスレッドプログラミングで使用されるような演算カーネルの概念を指します。

KLは以下のゴールを目指し設計されています:

  • 動的言語プログラムではパフォーマンスクリティカルとなる領域において実行されるよう設計されています。つまりモダンな機器上で可能な限り高速に実行されるよう設計されています。
  • Python や JavaScript のようなスクリプト言語にすでに馴染みがあればすぐに習得可能であるべきです。
  • KLプログラムを異なるアーキテクチャ、機器、CPU、GPU上で問題なく動作するようコンパイル可能であるべきです。

KLは Javascript に非常に近い構文を持つ言語ですが、プロシージャル, 強い型づけ であり low-level data layouts と持つという特徴を持ちます。「プロシージャル である」とは、 Javascript と異なり、関数(もしくはクロージャ)が言語中受け渡し自由なファーストクラスオブジェクト(first-class objects)では「なく」、かわりに関数は常にグローバルに宣言されます。 強い型づけ とは、KLプログラム中、すべての変数や関数のパラメータの型はコンパイル時に解決されることを意味します。実行時に解決されるような JavaScript などとは異なります。 low-level data layouts を持つということは、データのサイズや、メモリでのそれらの配置に関して、プログラマーが制御できるということを保証します。

サンプルの実行

このガイドはKLサンプルコードが沢山載っています。サンプルと実行結果例を読むだけではなく、学んだものを基にこれらサンプルに手を加え、どのように結果が変化するか実際に試すことをお勧めします。

KLコードを単独で実行(すなわち Fabric Engine 外で)するため、 KL tool があります。KL tool はこのガイドで目にする全ての出力結果の生成に使用されています。 Fabric Engine インストーラの一部として既にインストールされています。(インストーラは http://dist.fabric-engine.com/FabricEngine/latest/ こちらから)インストールプロセスの一環で、環境変数 FABRIC_DIR を設定したはずです。そのため KL tool は $FABRIC_DIR/bin に存在します。KL tool をインストールしたのであれば、サンプルコードをテキストファイルに保存し、コマンドラインから kl filename.kl として実行し、結果を得ます。

ヒント

KL tool には Fabric Engine アプリケーションの開発に役立つ様々なオプションがあります。 kl --help を実行し、利用可能なオプションと詳細を表示します。 kl --loadexts はカスタム Fabric Engine エクステンションのデバッグにとても役立つでしょう。

KL でHello World

言語の詳細に飛び込むまえに、まずは簡単なサンプルをいくつかお見せします。サンプルのすべての詳細について完璧に理解する必要はありません。KLプログラムがどのような感じなのか、どんなことができるのかについての基本的概念の把握に役立つと思います。

伝統に則り、ある言語における初めてのプログラムといえば hello ですね。KLでは “Hello, world!” プログラムは単純です:

/*
** Example: Hello World
*/

operator entry() {
  report("Hello, world!");
}

/*
** Output:

Hello, world!

*/

このプログラムを KL tool から実行すると、 “Hello, world!” と出力されます。

ここではこれ以上のことはあまりありません。ただいくつかのコンセプトがわかりますね。

  • entry オペレータこそが、KL tool から実行されるものです。KLは呼ばれたプログラムと呼んだ外の世界とをの場を分かちます。この場合、外の世界とは KL tool そのものを指します。 演算子 にオペレータについてのより深い論があります。
  • report 関数はテキストをどこへでも送信します。この場合 KL toolからの送信先は標準出力、コンソールアプリケーション(Node.js や Pythonなど)では標準エラーです。
  • "Hello, world!" は文字列定数です。KLでの文字列定数は、JavaScriptでのシンタックスと同一です。

KL でフィボナッチ数列

つぎに、洗練された例としてフィボナッチ数列の最初の方の項の計算をお見せします。フィボナッチ数列とは、最初の二項は0,1と定義され、以後どの項もその前の2つの項の和となる(すなわち 1, 2, 3, 5, 8 と続く)数列です。フィボナッチ数列のプログラミング言語での演算には幾通りもありますが、ここではKLの言語機能の解説のため、素朴な再帰を使います。

KLでフィボナッチ数列を生成するソースコード:

/*
** Example: Fibonacci Sequence
*/

/* Recursively compute the Fibonacci sequence.
** The first term is returned with n = 0
*/

function Integer fibonacci(Integer n) {
  if (n <= 1)
    return 1; // The first two terms (n=0 or n=1) are 1
  else
    return fibonacci(n - 2) + fibonacci(n - 1);
}

operator entry() {
  for (Integer i = 0; i < 10; ++i)
    report(fibonacci(i));
}

/*
** Output:

1
1
2
3
5
8
13
21
34
55

*/

この例で示される、KLの簡単な機能:

  • 関数とパラメータの宣言
  • 再帰
  • 条件文
  • ループ
  • コメント

KL でマンデルブロ集合

最後に、KLプログラムでマンデルブロ集合を生成し、結果をアスキーアートに出力してみます。マンデルブロ集合とは、複雑な再帰関数により定義された数学的な集合です。視覚的にとても見事なパターンを含むことでよく知られています。詳細は Wikipedia の記事 http://en.wikipedia.org/wiki/Mandelbrot_set を参照してください。

KLには、マンデルブロ集合の演算などの計算問題のため言語自体を拡張するような、とても強力な機能が備わっています。以下のコードに現れています。

/*
** Example: Mandelbrot Set
*/

struct Complex32 {
  Float32 re;
  Float32 im;
};

function Complex32(Float32 re, Float32 im) {
  this.re = re;
  this.im = im;
}

function Complex32 +(Complex32 lhs, Complex32 rhs) {
  return Complex32(lhs.re + rhs.re, lhs.im + rhs.im);
}

function Complex32 *(Complex32 lhs, Complex32 rhs) {
  return Complex32(lhs.re*rhs.re-lhs.im*rhs.im, lhs.re*rhs.im + lhs.im*rhs.re);
}

function Float32 Complex32.normSq() {
  return this.re*this.re + this.im*this.im;
}

function UInt8 computeDwell(Complex32 c) {
  Complex32 z = c;
  UInt8 count;
  for (count = 0; count < 255; ++count) {
    if (z.normSq() > 4)
      break;
    z = z*z + c;
  }
  return count;
}

operator entry()
{
  Complex32 z;
  for (Size row=9; row<=31; ++row) {
    z.im = Float32(4.0 * row / 40.0 - 2.0);
    String rowString;
    for (Size col=0; col<=78; ++col) {
      z.re = Float32(4.0 * col / 78.0 - 2.0);
      UInt8 dwell = computeDwell(z);

      if (dwell & 192)
        rowString += "#";
      else if (dwell & 48)
        rowString += "*";
      else if (dwell & 12)
        rowString += ".";
      else
        rowString += " ";
    }
    report(rowString);
  }
}

/*
** Output:

                                  .....                                        
                                .......#.                                      
                              ......**.....                                    
                            .......####*.....                                  
                         ..........####.........                               
                    ........*#**##########*...*..                              
               .............*#################....                             
            ...............###################....                             
          ......*..*.*...*#####################...                             
        ........*######*.######################*..                             
      ......*..################################...                             
############################################*.....                             
      ......*..################################...                             
        ........*######*.######################*..                             
          ......*..*.*...*#####################...                             
            ...............###################....                             
               .............*#################....                             
                    ........*#**##########*...*..                              
                         ..........####.........                               
                            .......####*.....                                  
                              ......**.....                                    
                                .......#.                                      
                                  .....                                        

*/

マンデルブロ集合の例で使用される、より洗練されたKLの機能:

  • 型のユーザ定義
  • コンストラクタ
  • 演算子オーバーロード
  • メソッド
  • ビット演算子
  • 可変長配列

このガイドの読み方

他の言語と違い、KLは動的言語で書かれたプログラムにパフォーマンスクリティカルなセクションを追加するために設計された言語です。そのためこのガイドは、すでにモダンなプログラム言語の基礎概念 ―たとえば型(type)、式(expression)、文(statement)、条件文、ループ文、return文、関数など―について、一定レベルの理解を前提とし記述します。

その言語にもつ概念、コンセプトを使用せず、コンピュータ言語での意味のあるサンプルを提供するのは難しいので、これ以降のガイドでは、それまでに説明していない概念を参照することがあります。先まで読み飛ばすか、そのまま読み進めるか自由です。

以降のガイドのレイアウト:

  • KLの文法 ではKLの文法について解説します。KL は JavaScript によく似たシンタックスをもちます(JavaScript同様, C-like 言語ですね) 。このため多くのプログラマに取って馴染みのある文法でしょう。もし JavaScript や C言語 が得意であれば、この節はスキップし先に進むと良いでしょう。必要になったらいつでも戻って参照できます。
  • KLの型システム ではKLでの型システムについて解説します。KLには基本的な型が豊富に付属します。例えば 整数、浮動小数点数、文字列、真偽、さらには構造体、配列、辞書などの派生型を含みます。
  • 関数と他のグローバルな宣言 では関数や、他のグローバル宣言されるものについて解説します。KLは基本的な関数(他の言語ではプロシージャと呼ばれることもある)をサポートします。さらに、より複雑な関数にまつわる概念、たとえば、関数プロトタイプ、メソッド、演算子オーバーロードについてや、グローバル定数や、外部モジュールのインポートについても記述しています。
  • 演算子・式 ではKLでサポートされるいくつかのペレータについて解説します。これらのオペレータを使用した式(expression)の幾つかの変奏についても解説します。また、変数とその他シンボルのスコープの管理規則についても説明します。
  • 文(Statements) ではKL中の関数本体で使用可能な文について解説します。