Chapelは、並列処理に重点を置いた高水準のプログラミング言語です。並列処理を簡単に、安全で、効率的に行うことができるように設計されています。Chapelは、C++、Java、Pythonなどの他のプログラミング言語の影響を受けています。
このチュートリアルでは、Chapelの基礎を学びます。Chapelのインストール方法、基本的な構文、データ型、制御構造、関数、クラスなどについて説明します。また、並列処理の記述方法についても説明します。
このチュートリアルは、Chapelの初心者向けに書かれています。Chapelの経験が豊富な方でも、このチュートリアルから何か新しいことを学ぶことができるかもしれません。
このチュートリアルが、Chapelの基礎を学び、並列処理を記述するための強力なツールを習得するのに役立つことを願っています。
__TOC__
Chapel は、並列処理に重点を置いた高水準のプログラミング言語です。2009年にクレイ・スーパーコンピュータ社によって最初に開発され、それ来、オープンソースプロジェクトとして開発が続けられています。Chapel は、C++、Java、Python などの他のプログラミング言語の影響を受けています。
Chapel の目標は、並列処理を簡単に、安全で、効率的に行うことができる言語を作ることです。そのために、Chapel には並列処理をサポートする多くの機能が用意されています。例えば、並列配列、並列関数、並列タスクなどがあります。Chapel には、並列処理を記述するための多くの高レベルの構文も用意されています。例えば、forall 文、par 文、task 文などがあります。
Chapel は、強力で用途の広いプログラミング言語です。並列処理を簡単に、安全で、効率的に行うことができる言語を探している人には最適です。
Chapelの基本を学ぶのであれば、処理系のインストールは必要なく、[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuhY7yosyS1Jz8jSUPFJzcvIVyvOLclIUlTStIdJQVTDVAA Attempt This Online]などのオンラインの実行環境をブラウザーから利用することが出来ます。
また、処理系をインストールする場合、DockerのコンテナやHomebrewのパッケージを利用することが出来ます。
そうではなく、ソースコードからビルドする場合は、GitHubでソースコードが公開されています。
Chapel は、コンパイル型言語なので、ソースコードを用意し、コンパイルして出来た実行ファイルを実行します。
Chapel のソースコードの拡張子は、.chpl を使うのが一般的です。
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuhY3Q8qLMktSc_I0lDxSc3LydRTK84tyUhSVNK0VgEBfX-Fx0-bHzZsfN-193LzncfPqx42rHzf0oKh93ND7uHHFi4Urni_Z9bhx5uOmbojZUCtgVgEA hello.chpl]:
writeln("Hello, world!");    // コンソールに「Hello, world!」と表示する
上記の、hello.chpl をエディタで編集し保存し以下のように実行します。
$ cat hello.chpl
writeln("Hello, world!");    // コンソールに「Hello, world!」と表示する
$ chpl hello.chpl
$ ./hello
Hello, world!
上記の１行からなるソースコードは、なにかの調べ物をするときには便利です。
しかし、このまま機能を加えていくと、どこからプログラムが始まるかなどが、コードが大規模になるとわかりにくくなります。
次のコードは、それらを改修した製品水準のものです。
[https://ato.pxeger.com/run?1=nVVdTxNBFH002V8x9gU1Iq8mxicf9G8QWKFJaQmfD4akM4vQsosQkZYWoUU-ulDbkiBabSn_w9fb2bZP_AXv3NnWfmmMySbtzs7ce-45597ZP5uYHp81Q9ns6eLC69GnP-8Vxh4ZDPgO8CJYSbAKIC7BOgcrC7wEUe6dCXl73UivAs_jyrQZCkWeTEzPhoC7rYNDWS7jh3q1CvwMOG6qAU8Bd_Ckwbyc3YpmpZMAvgvCAZ7pTYGvV-q_-A7iFsQJWHkQ7-s3t40PLvAkxQDrE4gyWKdgVdX3KG-6BVlM4-PtXuIr8A0QMeBXM-PB8IOHXtxufE0D38RI3t67xskPjR33N2rnCpywETphXWtgZp5rYBx-AWLDRx8VxqMxwxgbYyOvVLkjnf1ye1PGN4mqXlTifTt-8ncQDADiRu3ANBYycOTXiPT87fwFJpPZL3I7pvi3j2T1Wha2A8R6ALe2UicEJ9MdFKFp2oEfENe4kldY8D9WLK4oU3wQOx10-wlQ2BWWjArKj5W6Ud4tfrG5fiHt3WHBSiPTPm35_rDGTGRyMWQy4pW9MRjDRDJ24H3MoE1kdUudQTXxDFZiHYFlgagQhWVF0voPubHfFjEDgisg3X7gZBx-xgIz5vz8-JQZYETucdON9ohDmf-YWh5i_JIuUfvHS6zLQlLGMITrvXOb-Y6peyLWKxVvdasflViVJ3ENT247Xm5P5VIFrpOE58oCVkxGUdeSLGaaR47cKjWtm17XFEnFQ9U0KCQ2kFq_QgPXyxvefll53mdmh3hAbDlaVAg1vLtqrF6z76rp0VGfn-eBl5HIJDOXzHAwPMUWw8Elc27evB-4q8Z1VROR8OvglPqZX2D-KfacBUjDx2w5MheavB94ZugM_YZYe0uWiyklVfN_BivVVY32pBo0L2gwDcygouajlbBlzvZSQjHX1zzc6cjoa-K3-Cb1vTo-VKu_GzynYfVIoAaVBp2kDcXlueCCGcKxo4AW9uRHzFry0slWJTVkSuCe30CL9XK0ZbkUR2jXtRnsp6B5_Q19qIsfrAc11aOvlfikzVavJP6BdIcmjU3FZ_xuUuNjhyI7AzAcyrtG8_07jfscZSebtBndoafDXX_9gzN6yNzshFI4hsYZEJxnZM3pZwddMEAlCJf6B6m5oGgHfhfhCtXTAdB1edSIIF9XPQ7alxT12__B66p3di4ywTQ3NBQZaxvL77eHz3B1xVjRt7Z_ebcv8V8 hello_config.chpl]:
/*
 このプログラムは、概念的にはhello.chplと非常に似ていますが、
 構造化されたプログラミングスタイルを使用し、
 モジュール、設定定数、およびmain()手続きを明示的に定義するという点で異なります。
// 'Hello'という名前のモジュールを定義します。
// ソースファイルがモジュールを定義しない場合、拡張子".chpl"を除いたファイル名が、それに含まれるコードのモジュール名となります。
// したがって、hello.chplの自動モジュール名は'hello'になります。
module Hello {
  // 初期化式により、メッセージを出力するための設定定数として "message" を宣言します。
  //  初期化式により、型は自動的に文字列と推論されます。
  // 任意の設定定数や変数と同様に、デフォルト値は実行可能ファイルのコマンドラインで上書きすることができます
  // （例：--message="Good evening universe!"）。
  config const message = "Hello, world!";
  // モジュール内のトップレベルのコードは、Chapelプログラムの実行開始時にモジュールが初期化されるときに実行されます。
  // したがって、hello.chplでは、ファイルスコープでのwriteln()の存在は暗黙のモジュールの初期化の一部であり、
  // プログラムの起動時に実行されます（main()関数や他のトップレベルのコードがなかったため、これがプログラムが行うすべてです）。
  // ここでは、モジュールのmain()手続きを定義します。
  // これは、モジュールが初期化された後に実行されるプログラムのエントリーポイントです。
  // 明示的または暗黙的に使用するモジュールが初期化された後に実行されます。
  proc main() {
    writeln(message);
  }
}
内容は、山盛りのコメント通りですので、コンパイルして実行してみます。
$ chpl hello_config.chpl
$ ./hello_config
Hello, world!
$ ./hello_config --message="Good evening universe!"
Good evening universe!
$ ./hello_congig -h
FLAGS:
  -h, --help            : print this message
  -a, --about           : print compilation information
  -nl                : run program using n locales
                          (equivalent to setting the numLocales config const)
  -q, --quiet           : run program in quiet mode
  -v, --verbose         : run program in verbose mode
  -b, --blockreport     : report location of blocked threads on SIGINT
  -t, --taskreport      : report list of pending and executing tasks on SIGINT
  --gdb                 : run program in gdb
  -E=      : set the value of an environment variable
CONFIG VAR FLAGS:
  -s, --=  : set the value of a config var
  -f          : read in a file of config var assignments
CONFIG VARS:
Built-in config vars:
       printModuleInitOrder: bool
      dataParTasksPerLocale: int(64)
  dataParIgnoreRunningTasks: bool
      dataParMinGranularity: int(64)
                   memTrack: bool
                   memStats: bool
             memLeaksByType: bool
                   memLeaks: bool
                     memMax: uint(64)
               memThreshold: uint(64)
                     memLog: string
                memLeaksLog: string
             memLeaksByDesc: string
                 numLocales: int(64)
Hello config vars:
                    message: string
このようにChapelで作ったプログラムは、コマンドラインのハンドリングが処理系によって予めお膳立てされているので、コマンドラインインターフェイスは自ずと統一されます。
他方、Chapel以外で書かれたプログラムに特有のコマンドラインインターフェイスの作法があった場合、移植に工夫が必要になります。
Chapelでは、変数に値を代入することができます。変数名は英数字とアンダースコア（_）を使用できますが、数字で始めることはできません。
また、大文字と小文字は区別されます。
変数を宣言したときに初期値を与えるには、等号（=）を使用します。以下の例では、変数xを数値10で初期化しています。
var x = 10;
変数に代入された値は、後で変更することができます。以下の例では、変数xに数値20を再度代入しています。
x = 20;
以下は、2つ以上の変数を一度に宣言する例です。
 
var a = 1, b = 2, c = 3;
このように、コンマで区切って変数を列挙することで、それぞれの変数に対して別々の値を一度に代入することができます。上記の例では、aに1、bに2、cに3が代入されます。
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuhY3W8oSixQqFGwVDA2subjKizJLUnPyNJRAIko6ChWa1lwgphFQEpscF0h3Iki3jkISSJ2OQjKQMkZSnQhRnagDIpMgnCQwJxnCSda0hrgF6iSY0wA まとめ]:
var x = 10;
writeln("x = ", x);
x = 20;
writeln("x = ", x);
var a = 1, b = 2, c = 3;
writeln("a = ", a, ", b = ", b, ", c = ", c);
実行結果:
x = 10
x = 20
a = 1, b = 2, c = 3
{{コラム|Chapelでは代入は式ではなく文|2=Cファミリーでは代入は式なので
int a, b, c;
a = b = c = 0;
のように書くと
int a, b, c;
a = ( b = ( c = 0 ) );
という意味になります（代入演算子が右結合なのはこれが理由です）。
しかし、Chapelでは代入は演算子ではなく文なので連結することも、条件式に書くことも出来ません。
このため、結合方向を気にする必要はなくなりました（文は式と結合しないので）。
同様な方針を取った言語としては、最近では Go、古くは Fortran、Algol、Pascalがあります。
Chapelでは、変数の他に定数の宣言もサポートされています。
定数は初期化された後に値を変更できない変数と考えることができます。
Chapelでは、「実行時定数」と「パラメータ」の2つの種類の定数がサポートされており、それぞれ異なるキーワードで導入されます。
 を使って宣言し、実行時に値が確定する定数です。
実行時定数は、キーワード config で修飾すると、実行時のコマンドラインから値を変更することが出来ます。
const gravity = 9.8;
この例では、gravity という実行時定数を宣言しています（floatと推定されます）。
この実行時定数は、重力加速度を表す実行時定数であり、値は 9.8 であり、後から値を変更することはできません。
 を使って宣言し、コンパイル時に値が確定している定数です。コンパイル時定数とも呼ばれます。
param debug: bool = false;
この例では、debug というパラメータを bool 型と宣言しています。
このパラメータは名前から、デバッグ用のコードの有効無効を切り替えるのに使うと考えられます。
パラメータが、他の言語の条件コンパイルに相当する機能に使えます。
[https://ato.pxeger.com/run?1=jZBBDoJADEXjdk7xw0qJCEuVeJgBK05SBjLTwXgWN2z0UJ5GA6Is3TW_v33Juz3Ks26J-_4e5JRsnwtVNtYLKqc7I1ccsNtsc3VxRojtMvrl0XoqrXKVprOLbJPlSBKQc43bwzBTpRncaQ4EY6G9N5WtyYpSrXa6xpGKUO1RNA2_H5w0e5pBh-2IHMYROKXiAuVQafwPELHCtziwScjBk6AOLKZlgpiaPOJ0VPIxMxl6AQ まとめ]:
const gravity = 9.8;
writeln("gravity = ", gravity);
// gravity = 0.0; -- error: illegal lvalue in assignment
param debug: bool = false;
writeln("debug = ", debug);
// debug = true; 
/* error: illegal lvalue in assignment *
 * error: parameter set multiple times */
実行結果:
gravity = 9.8
debug = false
Chapelにおける識別子は、小文字または大文字の英字またはアンダースコア( _ )で始まり、任意の小文字、大文字、数字、アンダースコア( _ )、ドル記号( $ )のシーケンスで続く文字列です。
合法な例:
abc 
myInt 
_123
unit$
違法な例:
0abc  // 先頭に数字は使えない 
$unit // 先頭にドル記号( $ )は使えない
if    // キーワードは使えない
.xyz  // ドット( . )は識別子に使えない
Charplでは、ドル記号( $ )を識別子の2文字目以降であれば使うことが出来ます。
[TODO:分類と説明の充実]
以下の識別子は、将来の使用のために予約されているキーワードです。
lambda
pragma
primitive
Chapelには、様々なデータ型があります。その中でプリミティブ型は以下の通りです。
Chapelでは、変数は使う前に宣言する必要があり、その時にデータ型を明示的に指定します。また、宣言時に初期化を行うことが出来、その場合は型推論を行い型を省略できます。
いままで、ほとんどの例では変数の型を明示せずに型推論で型を決めていましたが、明示的に型を指定できます。
// 変数・定数と設定
var x: real = 3.14;         // real型の変数を宣言し3.14をセットする。
var flag: bool;             // bool型の変数flagを宣言し初期値はセットしない（暗黙のfalseがセットされる）。
var z = -2.0i;              // imag型の変数zを宣言し-2.0iをセットする。
const epsilon: real = 0.01; // real型の実行時定数epsilonを宣言し0.01をセットする
param debug: bool = false;  // bool型のコンパイル時定数debugを宣言しfalseをセットする。
config const n: int = 100;  // 実行時に設定可能な定数nを宣言し100で初期化（Ex: $ ./prog --n=4）
config param d: int = 4;    // コンパイル時に設定可能な定数dを宣言し4で初期化（Ex: $ chpl -sd=3 x.chpl） 
Chapelのプリミティブ型のほとんどは、デフォルトのビット幅で値を指定するための対応するリテラル形式をサポートしています。
他のビット幅の値は、型変換（キャストまたは型強制）を使って取得します。
bool型は、falseとtrueを2つのリテラル値としてサポートします：
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuhY3N5QlFikkWikk5efnKNgqlBSVplpzgcSSgLy0xJxiIJervCizJDUnTyNR01oBGejrK9jagfXAlSRhVQI2CGGMXkllQapVcUlRZl46UD1EDcgFCGNwKoG4G-p8mDcA bool.chpl]:
var a: bool = true;
var b = false;
writeln(a);             // => true
writeln(b);             // => false
writeln(a.type:string); // => bool
writeln(b.type:string); // => bool
上記のコードでは、真理値型の変数 a と b を宣言し、それぞれに true と false の値を代入しています。
writeln(a) および writeln(b) によって、それぞれの変数の値が出力されます。結果として、a の値は true であり、b の値は false であることが示されます。
writeln(a.type:string) および writeln(b.type:string) によって、それぞれの変数の型情報が出力されます。結果として、両変数の型は bool であることが示されます。
真理値型の変数は true または false のいずれかの値を持ちます。これを利用して条件分岐や論理演算を行うことができます。また、Chapelでは真理値型を使用してループの制御や条件式の評価など、プログラムの制御フローを制御するために広く使用されます。
Chapelには整数型があります。以下に、Chapelの整数型に関するコード例と解説を示します。
 
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuha3GEvKEosUEq0UMvNKFGwVDA2suUACSUC2rimEnQyW1DA00wQKGhuZm5lDxFOsFEpBEhYgcSNToGqu8qLMktScPI1ETWsFFKCvr2BrBzQdriIJuwpdU7iKZOwqwA6AK0rBrgjoGoRb9EoqC1KtikuKMvPSQcohSkAuNzPRRDiIOGXJuJUBAwjhLuzKoOHFBQl8aBzA4gIA int.chpl]:
var a: int = 10;
var b = -5;
var c: int(16) = 32767;
var d: uint(8) = 255;
writeln(a);              // => 10
writeln(b);              // => -5
writeln(c);              // => 32767
writeln(d);              // => 255
writeln(a.type:string);  // => int(64)
writeln(b.type:string);  // => int(64)
writeln(c.type:string);  // => int(16)
writeln(d.type:string);  // => uint(8)
上記のコードでは、整数型の変数 a、b、c、d を宣言し、それぞれに整数値を代入しています。
writeln 関数を使用して、それぞれの変数の値を出力しています。結果として、a の値は 10、b の値は -5、c の値は 32767、d の値は 255 であることが示されます。
writeln 関数を使用して、それぞれの変数の型情報も出力しています。結果として、変数 a と b の型はデフォルトの整数型 int(64) であり、変数 c の型は 16 ビットの整数型 int(16)、変数 d の型は 8 ビットの符号なし整数型 uint(8) であることが示されます。
Chapelでは、整数型を使用して数値演算や配列のインデックス指定、制御フローの条件式などを行うことができます。整数型のサイズはビット数で指定することもでき、デフォルトでは int(64) が使用されますが、必要に応じて異なるビット数の整数型を定義することもできます。
int型のリテラル値は、通常、10進数の列として記述されますが、0b/0B、0o/0O、0x/0Xの接頭辞により、2進数、8進数、16進数の値として表現することも可能です：
i = 0b1001; //   9
i = 0o177;  // 127
i = 0x1ff;  // 511
Chapelでは、負の整数リテラルは存在せず、正の整数リテラルに単項否定演算子（-）を適用するだけであることに注目すべきです。
uint型は独自のリテラル形式を持ちません。しかし、int(64)に収まらないがuint(64)に収まる整数リテラルは、符号なし整数値とみなされます。
したがって、以下の宣言では、最初の変数はint型、2番目の変数はuint型と推定されます。
var m = 2000000000;
var l = 1000000000000000;
より小さな整数をuintとして表現するためには、型変換（キャストまたは型強制）を使用する必要があります。
実数型は、10進数または指数型によるリテラル値をサポートしています：
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuha3mHjLEosUEq0UilITczTMTDStFaBAX1_BzORx8-THzc2PmzseN657um7-s6kbns7r5gJpSYJqMTZC0WJshFtLMkQLXDlUy-OmRY-b9zxuWvu4ue1x0_rHzY2Pmxc_blz9on3V85ZtjxtXIUzhKi_KLEnNydNI1CupLEi1Ki4pysxLBzoAaIytHdwPcGVJuJUB3Q1XlozfNK5EBVsFYz1DExSXQxz_dMNEoNteLFzxvH8fVxJQnZGeaaquoRG6J5_1tCPUJQPVGVQY6pkX6Bpao6ozNHvZsAmhEuFhTWt0q4FOBDkK4VmsSqDuQfgVqyoDPXNDC3NTLkiqgCYOWCIBAA real.chpl]:
var a: real(64);        // 64ビットの実数型
var b: real(32);        // 32ビットの実数型
var c: real;            // アーキテクチャに自然な実数型
writeln(a.type:string); // => real(64)
writeln(b.type:string); // => real(32)
writeln(c.type:string); // => real(64)
a = 3.14;               // 小数表現
b = 2.5e-12;            // 指数表現
c = 0x1.7p-1;           // 16進数表現
writeln(a);             // => 3.14
writeln(b);             // => 2.5e-12
writeln(c);             // => 0.71875
まず、a、b、cという名前の3つの変数を宣言しています。aは64ビットの実数型、bは32ビットの実数型、cはアーキテクチャによって決まるデフォルトの実数型です。
次に、各変数の型情報を出力しています。結果として、aの型はreal(64)、bの型はreal(32)、cの型はデフォルトのアーキテクチャに基づくreal(64)であることが示されます。
その後、各変数に値を代入しています。aには小数表現の3.14、bには指数表現の2.5e-12、cには16進数表現の0x1.7p-1が代入されています。
最後に、各変数の値を出力しています。結果として、aの値は3.14、bの値は2.5e-12、cの値は0.71875であることが示されます。
これにより、異なるビット幅の実数型を使用して値を表現し、それぞれのビット幅に基づく演算や計算を行うことができることがわかります。また、Chapelはさまざまな数値表現方法をサポートしており、小数表現、指数表現、16進数表現などを使用して実数値を代入することができます。
10進数形式では、整数リテラルと区別するために.を使用する必要があります。10.は、Chapelでは有効な浮動小数点リテラル値ではないことに注意してください。
これは、整数値に対してメソッド呼び出しを行う際の構文の曖昧さのためです。このため、代わりに10.0が使用されなければならない。
また、.707は0.707の短縮表記として有効です（特に推奨はしません）。
指数形式では、ベースとなる10進数値を整数値にしたり、大文字のEを使用して指数を指定することができることに注意してください。したがって、次の4つの代入の値はすべて等価である：
var f: real;
f = 123.0e2;
f = 123e2;
f = 123.0E2;
f = 123E2;
Chapelでは、虚数型を表現するためにキーワードimagが使用されます。
[https://ato.pxeger.com/run?1=hZLLTsJAFIYTl32KWcLCgi2gaYMbn2TalNoEWjIdNS6n4wXjwkRjjJIYIkJiiZcVLuRJ3B6LPIZTW1tIUGc5-b9_vjM53aG5jdtWs9cb7NDG6sb7SnUXE4Q15LSwXahVijr6PqUSqlWAXwDnwDvAnmbXN9PLl-j2VIoBIwVUZQ5Qld8BMwHScApAcAd8AsEj8CMInoEz4H1go9lx-HkwBhbmHdIecajVdAtYpvttS_MpcVw7flz01Dcz_Sxn_JET1lnO_KdPwqiOVLnszKkn9okc8DC25w_ARxCcf7z1o8OBZAhIkava4swCii_EhNHkNeqMo_uT6VkX2BWwYdqWNYisKUrW5HUdWYR4RENb2HU9irDvO7aLqJdJogbxWohYuJkoZ39V1BeVxWDxKPknLQkI7TxgLgmURUOyPekS_SzTFw imag.chpl]:
var a: imag(64);      // 64ビットの虚数型
var b: imag(32);      // 32ビットの虚数型
var c: imag;          // アーキテクチャに自然な虚数型
writeln(a.type:string);  // => imag(64)
writeln(b.type:string);  // => imag(32)
writeln(c.type:string);  // => imag(64)
a = 3.0i;             // 虚数リテラルを代入
b = 2.5:imag;         // imagに強制変換して虚数を代入
// c = 1.7; error: Cannot assign to imag(64) from real(64)
writeln(a);           // => 3.0i
writeln(b);           // => 2.5i
writeln(c);           // => 0.0i
最初の部分では、3つの異なる虚数型の変数a、b、cを宣言しています。aは64ビットの実数型の虚数を表し、bは32ビットの実数型の虚数を表します。cはアーキテクチャに自然な虚数型を表します。
また、writeln文を使用して各変数のデータ型を表示しています。
次に、虚数型の変数に値を代入する例です。aには虚数リテラル3.0iを代入しています。bには2.5をimagキーワードを使用して強制的に虚数型に変換して代入しています。一方、cには実数型の値1.7を代入しようとするとエラーが発生します。
複素数型は、リテラル値のネイティブフォーマットをサポートしていません。その代わり、複素数値は通常、実数値と虚数値の加算や減算によって表現される。例えば、以下のようになります：
[https://ato.pxeger.com/run?1=jZJNboMwEEalLnMKL00QjvkNJErv4iKXOiKGGLdNz5JNNu0VepeeptAJNRgUxQtkwftm3qA5f-UvrObl5fL5qp-99Ofh-40plB_q8uRvUF61F37aLhbvSmheSgxfnC2yzmqFdo-IEorc7ilMAnsZoQ7RHzXfNFoJWUAaEoqzEieRY3AqZuAeFwdWjPGuujvNAH71x36QOsaoOSoNVuM5ICOZnJJdhwE8nDbsph0Fxuxdvwctl-37eNJiKPMvYsFA-iQNk2zNPT-xpfA0Y0l5lhR7anBbwo3I3NwxoWYfmCrm0L52FqyDLDZ4JfdzPODhn0o0dM9rVe1vBlwIwP5e17hf518 complex.chpl]:
var cmplx1: complex;
writeln(cmplx1);                // => 0.0 + 0.0i
writeln((-9.0).type:string);    // => real(64)
writeln((0i).type:string);      // => imag(64)
writeln((-9.0+0i).type:string); // => complex(128)
writeln(sqrt(-9.0));            // => nan
writeln(sqrt(-9.0+0i));         // => 0.0 + 3.0i
writeln(sqrt(0i));              // => 0.0 + 0.0i
writeln((-9.0) ** 0.5);         // => nan
writeln((-9.0+0i) ** 0.5);      // => 1.83697e-16 + 3.0i
writeln((0i) ** 0.5);           // => 0.0 - 0.0i
writeln(abs(3.0+4.0i));         // => 5.0
writeln(carg(3.0+4.0i));        // => 0.927295
writeln(conjg(3.0+4.0i));       // => 3.0 - 4.0i
writeln(cproj(3.0+4.0i));       // => 3.0 + 4.0i
cmplx1は複素数型の変数で、初期値は指定されていません。そのため、初期化されていない変数はデフォルトで0.0 + 0.0iとなります。writeln文によってcmplx1の値が出力されます。
typeプロパティを使って、数値の型を表す文字列を取得しています。-9.0は実数型（real）であり、0iは虚数型（imag）であり、-9.0+0iは複素数型（complex）です。それぞれの値の型が出力されます。
sqrt関数は平方根を計算する関数です。-9.0の平方根は実数では表現できないため、結果はNaN（非数）になります。-9.0+0iおよび0iの平方根は複素数として計算され、結果が出力されます。
**演算子はべき乗を計算する演算子です。-9.0の0.5乗は実数では表現できないため、結果はNaNになります。-9.0+0iおよび0iの0.5乗は複素数として計算され、結果が出力されます。
abs関数は複素数の絶対値を計算します。ここでは、複素数3.0+4.0iの絶対値を求めています。絶対値は複素数の大きさを表し、この場合は5.0となります。
carg関数は複素数の偏角を計算します。ここでは、複素数3.0+4.0iの偏角を求めています。偏角は複素平面上での角度を表し、この場合は約0.927295となります。
conjg関数は複素数の共役を計算します。ここでは、複素数3.0+4.0iの共役を求めています。共役は虚部の符号を逆転させた複素数を表し、この場合は3.0-4.0iとなります。
cproj関数は複素数の射影を計算します。ここでは、複素数3.0+4.0iの射影を求めています。射影は複素数そのものを表し、この場合は3.0+4.0iとなります。
これらの関数は複素数に対してさまざまな演算を行い、複素数の性質や値を操作するためのものです。それぞれの関数がどのような計算を行っているかを理解し、複素数に関する処理を行う際に利用することができます。
文字列のリテラル値は、一重引用符または二重引用符を使って表現することができます。例えば、次のような文字列は、合法的な文字列値です：
var s: string;
s = "hello";
s = 'hi';
これによる影響としては、文字列リテラル内で他のタイプの引用符を追加作業なしで使用できることです。
s = "he said, 'hi there!"";
プログラミングを行っていると、ある型の値を別の型に変換する必要が生じます。
[https://ato.pxeger.com/run?1=lVJNSwJBGIaO_ophQVDIj6xMXDr1E7p6WWS3BnRXZteyWzNWGIZG0JdCGGlFURkRZBr9j66vu9rJv9DMqn1cioa5vPB8vrzV8-SyklFTtVoja2mB2NvE4opCkIniyLQI1pfQPJKmItMzkuzxrBJsqZpPSkheMyH5vKafw7BucYw3m9ClSWTyH7TWMmp8yOZjnAP8nGwKpXBuNjoX41q_SIVz3tyfaiIk5uApGfEXCgmuLzrjB3rplC771wcuQuOISHBuWhYIoiqpEeTTHrvyIj_30r4G1x7_9Na-jyKDUMeutL1bcB72B52KUzl8bx8DvbVPinZ92ylXB51C0lBJEhv6oLPtEUk5TZNRIIBUQgwSRwuKrhsWUkwTL-nIMsZdkEaM9Gdsj8sT_eVRX6DXzlGpV3_uVTaAXgG7gfwZsBbkC0B37NfN_jnl9naz7Ow3e6zVbTe6T0Vge3b9HugW0DbQIqxT55QCZUAfge0APQZWtMt3_fyLs34BjInU7jKT6YwojObd-P9qPbyt0YmNT-0D coercion.chpl]:
var s : string = "1234";
writef("\"%s\"(%s) : int = %u\n", s, s.type:string, s:int);
s = "0x5678";
writef("\"%s\"(%s) : int = 0x%xu\n", s, s.type:string, s:int);
var i = 1;    // int(64)と推論
var f = 2.73; // real(64)と
writef("i.type = %s, f.type = %s\n", i.type:string, f.type:string);
f = i; // 合法：暗黙の型変換（coercion）
// i = f; -- error: Cannot assign to int(64) from real(64)
i = f:int; // intに明示的なキャストが必要（小数点以下を失うほか、桁あふれする可能性も）
var cmp = i == f; // 合法：暗黙の型変換（coercion）
実行結果:
"1234"(string) : int = 1234
"0x5678"(string) : int = 0x5678
i.type = int(64), f.type = real(64)
などが示されています。特に、キャスト以外にも .type プロパティや writef() といった飛び道具がいきなり出てきましたが、Chapelのプログラミングに頻繁に登場するので、この機会におぼえましょう。
refは、C++の参照と似たような動作をします。
Chapelでは、refは初期化された変数以外の変数とエイリアスを作ることはできません。
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuha3GJXLEosUMhVsFQwNrLmKUtMUioDsTGuu8qLMktScPI1MHQUlBVtbBSUdhSJNawV9fQVbO6BakJChARdIo66hkbG1AgoAqnq6pPPZ1A2Zj5smgVizt7zf01Gk8Lhx9dP-puetyx83Tn3c1PO4cdnjxpbHTd3v93TitxBkB0gQRHOBXGgJBdaoloINL0K2FCL0tLXjceN6hUyCFsHMBUnA2FyQsIIGGSzoAA references.chpl]:
var i = 10;
ref r = i;
writeln(i, " == ", r); // => 10 == 10
i = -123;              // 変数iを変更（r に参照されている）
writeln(i, " == ", r); // => -123 == -123
r = 99999999;          // 参照rを変更（参照先は i）
writeln(i, " == ", r); // => 99999999 == 99999999
同じスコープの変数の参照を作っても、別名が出来るだけであまり楽しいことはありませんが、プロシージャの引数に参照を使うと、文字通り参照渡しが可能となり、呼び出し元の変数に値を返すことが出来ます。
Chapelでは、キーワード enum を使って列挙型（enumeration type）を定義することができます。列挙型は特定の値のセットを表し、それぞれの値に名前を付けることができます。
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuhY3_6bmleYqFKcmFufnKVQrBBcUZeal6ygEl-bmphbpKDiWlpTm5ukohGfmlaQWKdRac5UlFikUK9hCtehBFFpzcRWn5qQmlwClqrkUgKA8IzUPrgZsqEJKvkJ5UWZJak6ehtKzGUuVNK0xVYJNQ1H5dEk_NpUQh6GofL68G5tKqNNRzGxbA1JZywUJBGhYwMIEAA enum.chpl]:
enum season { Spring, Summer, Autumn, Winter };
var s = season.Summer;
select s {
    when season.Spring do writeln("春");
    when season.Summer do writeln("夏");
    when season.Autumn do writeln("秋");
    when season.Winter do writeln("冬");
}
実行結果:
夏
構造型( Structured Types )には、
があります。
クラスは、変数や定数（フィールド）および関数やイテレータ（メソッド）を含むことができる型です。
新しいクラスは、キーワードclassを使用して宣言されます。
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuhY31ybnJBYXKwTkZ-aVKFRzKSiUJRYpVOgoVFopAEWsuYAiBUX5yUACpCAlH8hXUCgvyixJzcnTUKpQsFVQ0gGpB5KVEE6lpjVXLRcXyJyCEqBQXmo5xHgNI0MdBRNToHRBiR7YPGuYMiMUdSCDdIFqQaZbgpUbQdVDHA11O8wPAA point.chpl]:
class Point {
  var x, y: int;
  proc print do
    writeln("x = ", x, ", y = ", y);
}
var pt = new Point(21, 45);
pt.print;
var pt2 = new Point(y = -1, x = 9);
pt2.print;
x = 21, y = 45
x = 9, y = -1
は、コンストラクタを呼び出すことによりクラスのインスタンスを作成します。
上記のクラスPointは、コンストラクタを宣言していないため、コンパイラが生成したコンストラクタが使用されます。
コンパイラが生成したコンストラクタは、クラス内の各フィールドに対する引数を持っています。
クラスが初期化されると、そのメソッドを呼び出すことができます。
クラスには、解放方法を決定するさまざまなメモリ管理戦略があります。
あらためて詳しく説明しますが、今のところ、new Point(...)は、new owned Point(...)と書いたのと同じです。
ownedはこれらのメモリ管理戦略の一つです。
の4つです。
// unmは手動で管理されるインスタンスを参照します。
var unm: unmanaged Point = new unmanaged Point();
// メモリを解放するためには、deleteを呼び出す必要があります。
delete unm;
// ownが参照するインスタンスは、スコープ外になると削除されます。
var own: owned Point = new owned Point(1, 10);
//特定のインスタンスに対して同時に複数のowned Pointが参照することはできませんが、所有権は他の変数に移動することができます。
var own2 = new Point(1, 10);
assert(own.type == own2.type);
// 上記の例では、new Point(...)はnew owned Point(...)の略記法として使用できます。なぜなら、クラスのデフォルトのメモリ管理戦略はownedであるためです。
// shareが参照するインスタンスは参照カウントされます。
// つまり、複数のshared Point変数が同じインスタンスを参照し、最後の変数がスコープ外になると解放されます。
var share: shared Point = new shared Point(1, 10);
var tmp: borrowed Point = (new owned Point(1, 10)).borrow();
// tmpが参照するインスタンスは、スコープ外になると削除されます。所有権は他の変数に移動することはできません。
// 他のクラスポインタから借用することも可能です。その方法の1つは、borrow()メソッドを直接呼び出すことです。
var b1 = own.borrow();
レコードは、変数や定数（フィールド）だけでなく、関数やイテレータ（メソッド）も含めることができる型です。
レコードはクラスと多くの類似点がありますが、いくつか重要な違いがあります。
クラスは継承と仮想ディスパッチをサポートしていますが、レコードはサポートしていません。
異なるクラス変数は同じインスタンスを参照できますが、レコード変数は異なるメモリを参照します。
コピー初期化や代入はレコードに対して実装できますが、クラスにはできません。
レコード型は、キーワードrecordを使用して宣言することができます。
[https://ato.pxeger.com/run?1=m70sOSOxIDVnwYKlpSVpuha3GCuKUpPzi1IU3FPznfNBjGouBYWyxCKFnPy89MyS0pRUHYWcxBIwy0qhKDUxx5qrlouroCg_WSE3MTNPQxOuozizJLVYwVYhGshXUFB6Nnfjk11rXi5vVVJAAbZ2Cnmp5XALNQyNLfXMzcyNDcwsdBSMTfXMLAwsTS0NNXUgxjxu2v64ufNxc_fj5j2Pm3c_blr1uHnW4-aVj5v7Hzcte9y0UwnTRFNDPSNDUyNzoIG6xsZ6FqZm5uYWCAM3PG5eBTaw-XHTjqdLVj6b1v60f4MSdufpGugZGBia6CgADTWBGRNrDSTS8osU8hJzUxUy8yB-10vJBwWJQkq-Atiq8iKgaE6eBkiRDkRJNIgdqwkMQ0gEQOMBFh8A record.chpl]:
record GeoCoord {
  var longitude, latitude: real;
}
proc main() {
  var sites = [
    "東京駅"                 => new GeoCoord(139.7673068, 35.6809591),
    "シドニー・オペラハウス" => new GeoCoord(151.215278, -33.856778),
    "グリニッジ天文台"       => new GeoCoord(-0.0014, 51.4778),
  ];
  for name in sites.domain do 
    writeln(name, sites[name]);
}
グリニッジ天文台(longitude = -0.0014, latitude = 51.4778)
東京駅(longitude = 139.767, latitude = 35.681)
シドニー・オペラハウス(longitude = 151.215, latitude = -33.8568)
Chapelのユニオン( union )は、複数の異なる型の値を同じメモリ領域で保持する仕組みです。
ここまではCと同じですが、Chapelの union では、有効なフィールドは1つだけです。
どのフィールドが有効かは、最後に代入されたフィールドによってかわります。
[https://ato.pxeger.com/run?1=ndAxDoJAEAXQ2G5v_0sogIiFBuIt5ACbdZVJ1oUMrMYYTmJDo4fyNIKAMbGznMyfl8m_PVQuS23a9u7qfbB-zubOUmGR4SqAk2RQArJ1Ok6cgLU0qWiEKLlQOEqynv9JuwRZn3UhYYNFvExFFAFnplob67mQ_RSaueigXJq611SudwhAxuiDNBgekErpqhLfp-QPMndyHK5-aPqf5jc9zVRlfXB7KbWX-d2qGdoZS5rKegE union.chpl]:
union U {
  var i: int;
  var r: real;
}
proc main() {
  var u: U;
  u.i = 123;
//  writeln(u.r); error: halt reached - illegal union access
  writeln(u.i);
  u.r = 2.73;
//  writeln(u.i); error: halt reached - illegal union access
  writeln(u.r);
  writeln(isUnionType(U));
}
123
2.73
true
var t = (1, 3.2, "xyz");
writeln("t = ", t, ", x.type = ", t.type:string);
writeln("t.size = ", t.size);
for x in t do
  write(x, "; ");
writeln();
writeln("t(0) = ", t(0));
writeln("t(1) = ", t(1));
writeln("t(2) = ", t(2));
var (a, b, _) = t;
writeln("a = ", a, ", b = ", b);
for prime in ( 2, 3, 5, 7, 11) do
  write(prime, ", ");
writeln();
t = (1, 3.2, xyz), x.type = (int(64),real(64),string)
t.size = 3
1; 3.2; xyz; 
t(0) = 1
t(1) = 3.2
t(2) = xyz
a = 1, b = 3.2
2, 3, 5, 7, 11, 
データ並列型( data parallel types )には、
があります。
範囲（Range）は整数などの一定の値のシーケンスを表し、通常、下限と上限の境界を定義します。
範囲の値は、.. 演算子を使用して指定することができます。下限は .. の左側に指定し、上限は右側に指定します。
// r は範囲で、1 から 10、1 から 9、10 から 1 までです。
// r.type は range です。
// r:array は、1 から 10、1 から 9、10 から 1 までの配列です。
for r in (1..10, 1..<10, 1..10 by -1) do
  writeln("r = ", r, ", r.type = ", r.type:string, ", r:array = [", for i in r do i, "]");
writeln();
var sum = 0;      // sum は 0 で初期化された変数です。
for i in 1..10 do // i は 1 から 10 までの整数です。
  sum += i;       // sum に i を加算します。
writeln("sum = ", sum);
writeln();
// reduce 演算子は、範囲の要素に左辺のメソッドを順に適用します。
// + reduce (1..10) は、1 から 10 の合計を計算します。
writeln("+ reduce (1..10) = ", + reduce (1..10));
r = 1..10, r.type = range(int(64),bounded,false), r:array = [1 2 3 4 5 6 7 8 9 10]
r = 1..9, r.type = range(int(64),bounded,false), r:array = [1 2 3 4 5 6 7 8 9]
r = 1..10 by -1, r.type = range(int(64),bounded,true), r:array = [10 9 8 7 6 5 4 3 2 1]
sum = 55
+ reduce (1..10) = 55
 キーワードは、範囲を表す値のシーケンスがそのストライドに対してどのようにアライメントされるかを指定するために使用されます。 1 または -1 以外のストライドを持つ範囲では、アライメントは重要です。たとえば、ストライドが 2 の範囲は 2 の倍数であるインデックスのみをサポートします。範囲の値のシーケンスがストライドに対して整列していない場合、範囲は空になります。
for i in 1..10 by 2 do
  write(i, " ");
writeln();
for i in 1..10 by 2 align 2 do
  write(i, " ");
writeln();
1 3 5 7 9 
2 4 6 8 10 
最初のコードは、範囲を 1 から 10 まで、ストライドを 2 で走査します。つまり、1、3、5、7、9 を出力します。
2 番目のコードは、範囲を 1 から 10 まで、ストライドを 2 で走査し、2 でアラインします。つまり、2 の倍数である 2、4、6、8、10 を出力します。
ドメインは、イテレーション空間の指定、配列の定義、スライスなどの集約操作を定義するために使用されるインデックス集合の一級表現です。
config const n = 10;
var RD: domain(3) = {1..n, 1..n, 1..n};
writeln("RD = ", RD, ", RD.type = ", RD.type:string);
// expandメソッドは、オフセット引数の符号に応じて拡張または縮小された新しいドメインを返します。
writeln("RD.expand((1,1,1)) = ", RD.expand((1,1,1)));
writeln("RD.expand((-1,-1,-1)) = ", RD.expand((-1,-1,-1)));
// exteriorメソッドは、現在のドメインの外部部分である新しいドメインを返します。
// 正のオフセットは高い範囲から外部部分を取得し、負のオフセットは低い範囲から外部部分を取得します。
writeln("RD.exterior((1,1,1)) = ", RD.exterior((1,1,1)));
writeln("RD.exterior((-1,-1,-1)) = ", RD.exterior((-1,-1,-1)));
// interiorメソッドは、現在のドメインの内部部分である新しいドメインを返します。
// オフセットの符号は、外部の場合と同様に高い範囲または低い範囲を使用することを意味します。
writeln("RD.interior((1,1,1)) = ", RD.interior((1,1,1)));
writeln("RD.interior((-1,-1,-1)) = ", RD.interior((-1,-1,-1)));
// translateメソッドは、オフセットで現在のドメインを移動した新しいドメインを返します。
writeln("RD.translate((1,1,1)) = ", RD.translate((1,1,1)));
writeln("RD.translate((-1,-1,-1)) = ", RD.translate((-1,-1,-1)));
writeln();
// サブドメインは、親ドメインを基準に宣言されるため、親と同じタイプを持つドメインです。
// サブドメインは、親ドメインのインデックスセットの部分集合を表しますが、この制約は現在の実装では強制されていません。
//矩形のサブドメインを作成します。
var RSD1, RSD2 : subdomain(RD);
// サブドメインは最初は空です。
writeln("RSD1 = ", RSD1, ", RSD1.type = ", RSD1.type:string);
writeln("RSD2 = ", RSD2, ", RSD2.type = ", RSD2.type:string);
writeln();
// スライシングを使用して元の矩形ドメインの一部を選択することができます。
RSD1 = RD[..n/2, .., ..];   // ドメインの半分を取得
RSD2 = RD[n/2+1.., .., ..]; // 残りの半分を取得
writeln("RSD1 = ", RSD1, ", RSD1.type = ", RSD1.type:string);
writeln("RSD2 = ", RSD2, ", RSD2.type = ", RSD2.type:string);
// 正規ドメインのスパースなサブドメインを作成します。
var SSD: sparse subdomain(RD);
writeln("SSD = ", SSD, ", SSD.type = ", SSD.type:string); // 最初は空です。
RD = {1..10, 1..10, 1..10}, RD.type = domain(3,int(64),false)
RD.expand((1,1,1)) = {0..11, 0..11, 0..11}
RD.expand((-1,-1,-1)) = {2..9, 2..9, 2..9}
RD.exterior((1,1,1)) = {11..11, 11..11, 11..11}
RD.exterior((-1,-1,-1)) = {0..0, 0..0, 0..0}
RD.interior((1,1,1)) = {10..10, 10..10, 10..10}
RD.interior((-1,-1,-1)) = {1..1, 1..1, 1..1}
RD.translate((1,1,1)) = {2..11, 2..11, 2..11}
RD.translate((-1,-1,-1)) = {0..9, 0..9, 0..9}
RSD1 = {1..0, 1..0, 1..0}, RSD1.type = domain(3,int(64),false)
RSD2 = {1..0, 1..0, 1..0}, RSD2.type = domain(3,int(64),false)
RSD1 = {1..5, 1..10, 1..10}, RSD1.type = domain(3,int(64),false)
RSD2 = {6..10, 1..10, 1..10}, RSD2.type = domain(3,int(64),false)
SSD = {
}
, SSD.type = DefaultSparseDom(3,int(64),domain(3,int(64),false))
ドメインマップ（Domain Maps）は、Chapelプログラムでドメインと配列のマッピング方法を指定するために使用されます。ドメインマップに関連するキーワードとその説明をコードを交えて解説します。
dmapped（ドメインマップの指定） 
は、ドメインまたは配列のマッピング方法を指定するために使用されます。以下のコード例では、キーワードdmappedを使用してドメインマップを指定しています。
use BlockDist;
type BlockDom = domain(2) dmapped Block({1..5,1..6});
dmap（ドメインマップの作成） 
は、ドメインマップのインスタンスを作成するために使用されます。以下のコード例では、キーワードdmapを使用してドメインマップを作成しています。
use BlockDist;
var MyBlockDist: dmap(Block(rank=2)) = new dmap(new Block({1..5,1..6}));
ドメインリテラル（Domain Literal） 
ドメインリテラルは、ドメインの範囲を指定するために使用されます。以下のコード例では、ドメインリテラルを使用してドメインの範囲を指定しています。
use BlockDist;
var MyDomLiteral = {1..2,1..3};
ドメイン代入（Domain Assignment） 
ドメイン代入は、ドメインのインデックスセットを右辺の式から左辺のドメインに転送する操作です。以下のコード例では、ドメイン代入が行われています。
use BlockDist;
var Dom1: domain(2) dmapped Block({1..5,1..6}) = {1..5,1..6};
var Dom2: domain(2) = Dom1;
Chapelでは、配列は配列のインデックスセットを指定する角かっこで囲まれた式によって指定されます。
その後に配列の要素の型が続きます。矩形配列は、インデックスが整数または整数のタプルであり、標準の多次元、直交座標のインデックスセットをサポートします。
[https://ato.pxeger.com/run?1=zZXNbtpAEMePlfwUq5ygch1214gKxJMkOVgBGkfURMT9yA0joYIACaVFJI3aEjUB0rS0lSKlapO8RqVejTE55RU667UNtsiBHipu3vXszP83OzN71NvcUnay-W739Jmee_T4z4Pfq6vIPvtpGsPbStOqdpBS3Ishs7xvDd_aN2em0TFLhmm8AwPr-_txqQ-_JscD-wSOHJrluvBcKTpnkmgNS1JsA6manhJeFFU9m9ciK467NFoRHSPR-5D0vZ3sdN9ZJnf1oqo9mdpkCk8VVZux4hvRlCCA6tv2pWm0cSwgHf-DdMylY9BezCr5oHjsh8eeMBwUj-eJx2HxOCTeUcz2QR2x25_so6FpDBLe13DSM-yLLigeN14BD4MxesBjlU5gc_Tro1U5dTGYlwiJQigSk2Ipvk6wdcJZQzg3kJsGY8C9BJLxv6Gph1o3y7V4mNs4H_0ojeufTaN_HzGVpDiDpHEpvpSQVmUwun4NKFarYRoH93CAH0yolFgihHH7Ytz-xmNbrXOzXPKhyEx7zfYQAV9rRERURHERJUSE8YZHRBYgIr4m4qklQSIyj4iEiUiQyP5Ssy6HDKragfD2mw_jasvvKbCnrOJmr8blouAxVygiFcYacoYEyhSQmuSDgvPRBfior5B62mmQj87jo2E-GuRzVfDm8euOWKXmtNIoeggTYolEyy9lpvm4wUtLDpfWZkHb1RE7Lqe8-5D5rNZEdhmaN7ADfcecWl9vJv19f5bgUOPdXVWt5sHousmD313VBLhkJZ9HEVVE21F22cyTB5ApCAipOaiCdBptI30rq8EGcmzcE9DFbNa62ZUXyK4MZ9c1niGZ5W7dDR7IsDwvw3I4w7KfYf6-u8-899z_BQ array.chpl]:
// 空の配列 ary0 を定義し、その属性を表示する
var ary0: [1..0] int;
writeln("ary0 = ", ary0, ", ary0.type = ", ary0.type:string, ", ary0.domain = ", ary0.domain);
// 長さ10の配列 ary1 を定義し、その属性を表示する
var ary1: [1..10] real;
writeln("ary1 = ", ary1, ", ary1.type = ", ary1.type:string, ", ary1.domain = ", ary1.domain);
// 配列ary1の2番目と7番目の要素を指定して、値を代入する
ary1(2) = 20.0;
ary1(7) = 70.0;
// ary1の属性と値を表示する
writeln("ary1 = ", ary1, ", ary1.type = ", ary1.type:string, ", ary1.domain = ", ary1.domain);
// 配列ary1の3番目から5番目の要素に一括で値を代入する
ary1(3..5) = 35.5;
// ary1の属性と値を表示する
writeln("ary1 = ", ary1, ", ary1.type = ", ary1.type:string, ", ary1.domain = ", ary1.domain);
// 配列ary1全体に同じ値を代入する
ary1 = 123.7;
// ary1の属性と値を表示する
writeln("ary1 = ", ary1, ", ary1.type = ", ary1.type:string, ", ary1.domain = ", ary1.domain);
// 整数値を含む配列ary2を定義する
var ary2 = [2, 3, 5, 7, 11];
// ary2の属性と値を表示する
writeln("ary2 = ", ary2, ", ary2.type = ", ary2.type:string, ", ary2.domain = ", ary2.domain);
// 等差数列を生成して、ary3に代入する
var ary3 = for i in 1..10 do i:real;
// ary3の属性と値を表示する
writeln("ary3 = ", ary3, ", ary3.type = ", ary3.type:string, ", ary3.domain = ", ary3.domain);
// ary3の要素全体に2倍する
ary3 *= 2;
// ary3の属性と値を表示する
writeln("ary3 = ", ary3, ", ary3.type = ", ary3.type:string, ", ary3.domain = ", ary3.domain);
// 4x4の行列ary4を定義する
const n = 4;
var ary4: [1..n, 1..n] real;
// 配列ary4の対角要素に1を代入する（単位行列）
forall (i, j) in ary4.domain do
  if i == j then
    ary4(i, j) = 1.0;
// ary4の属性と値を表示する
writeln("ary4 = \n", ary4, ",\n ary4.type = ", ary4.type:string, ", ary4.domain = ", ary4.domain);
実行結果:
ary0 = , ary0.type = [domain(1,int(64),false)] int(64), ary0.domain = {1..0}
ary1 = 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0, ary1.type = [domain(1,int(64),false)] real(64), ary1.domain = {1..10}
ary1 = 0.0 20.0 0.0 0.0 0.0 0.0 70.0 0.0 0.0 0.0, ary1.type = [domain(1,int(64),false)] real(64), ary1.domain = {1..10}
ary1 = 0.0 20.0 35.5 35.5 35.5 0.0 70.0 0.0 0.0 0.0, ary1.type = [domain(1,int(64),false)] real(64), ary1.domain = {1..10}
ary1 = 123.7 123.7 123.7 123.7 123.7 123.7 123.7 123.7 123.7 123.7, ary1.type = [domain(1,int(64),false)] real(64), ary1.domain = {1..10}
ary2 = 2 3 5 7 11, ary2.type = [domain(1,int(64),false)] int(64), ary2.domain = {0..4}
ary3 = 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 10.0, ary3.type = [domain(1,int(64),false)] real(64), ary3.domain = {1..10}
ary3 = 2.0 4.0 6.0 8.0 10.0 12.0 14.0 16.0 18.0 20.0, ary3.type = [domain(1,int(64),false)] real(64), ary3.domain = {1..10}
ary4 = 
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0,
 ary4.type = [domain(2,int(64),false)] real(64), ary4.domain = {1..4, 1..4}
{{コラム|配列の添字の開始は 0 か？ 1 か？|2=Chapelの配列の添字は、宣言時に明示したりドメインで指定できるので、どちらにすることも出来ます。また0/1以外の数（例えば 2; エラトステネスの篩の実装例では実際に2にしています）。
ですが、配列リテラルのように配列のインデックスの開始値を明示しない配列もあります。このうような場合は、バージョン1.21までは１から開始し、バージョン1.22以降は0から開始します。
このため 1.21 と 1.22 の間でChapelのソースコードには非互換性があります。
この影響は、可変長引数を持つ手続きの引数順位や、多次元配列のdomainのdim()のインデックスにもあります。
バージョン1.22のリリースは、2020年4月とそれほど昔ではないので、サンプルコードを参照したりドキュメントを読むときは、どのバージョンを想定しているのか注意が必要です。
また、コードを書く上では、添字の開始を0や1と決めつけずに、array.domain.lowを使ってアクセスするなど、予防的なコードを書きましょう。
配列の添字（=ドメイン）には、文字列など整数でない型を用いることも出来ます。
proc main() {
    var ages = [ "John" => 25, "Mary" => 30, "Alice" => 28 ];
    // 要素へのアクセス
    writeln("ages[\"John\"] = ", ages["John"]);  // 25
    // 要素の変更
    ages["Mary"] = 32;
    // ドメインを使った反復
    for name in ages.domain do 
        write(name, "(",ages[name], ") ");
    writeln();
}
ages["John"] = 25
Mary(32) John(25) Alice(28) 
配列と結びついたドメインを動的に変更することで連想配列に近いことが出来ます。
proc main() {
    var Colours = {"Red", "Green", "Blue"};
    var rgb: [Colours] int;
    rgb["Red"]   = 0xff0000;
    rgb["Green"] = 0x00ff00;
    rgb["Blue"]  = 0x0000ff;
    for colour in Colours do 
        writef("%s(#%06xu) ", colour, rgb[colour]);
    writeln();
    Colours += "Yellow";
    rgb["Yellow"] = rgb["Red"] + rgb["Green"]; 
    for colour in Colours do 
        writef("%s(#%06xu) ", colour, rgb[colour]);
    writeln();
    Colours += "White";
    rgb["White"] = rgb["Red"] + rgb["Green"] + rgb["Blue"]; 
    Colours += "Black";
    rgb["Black"] = 0;
    for colour in Colours do 
        writef("%s(#%06xu) ", colour, rgb[colour]);
    writeln();
    Colours -= "Yellow";
    for colour in Colours do 
        writef("%s(#%06xu) ", colour, rgb[colour]);
    writeln();
    Colours += "Yellow";
    for colour in Colours do 
        writef("%s(#%06xu) ", colour, rgb[colour]);
    writeln();
}
Blue(#0000ff) Red(#ff0000) Green(#00ff00) 
Yellow(#ffff00) Blue(#0000ff) Red(#ff0000) Green(#00ff00) 
Yellow(#ffff00) White(#ffffff) Black(#000000) Red(#ff0000) Blue(#0000ff) Green(#00ff00) 
White(#ffffff) Black(#000000) Red(#ff0000) Blue(#0000ff) Green(#00ff00) 
Yellow(#000000) White(#ffffff) Black(#000000) Red(#ff0000) Blue(#0000ff) Green(#00ff00) 
同期型( synchronization types )には、
があります。
Chapelでは、多くの種類の式と演算子がサポートされています。ここでは、最もよく使用される式と演算子のいくつかについて説明します。
数学演算子には、加算、減算、乗算、除算、べき乗、剰余があります。次の例は、これらの演算子の使用方法を示しています。
var a: int = 1234, b: int = 5678;
a = a + b;  // 加算
a = a - b;  // 減算
a = a * b;  // 乗算
a = a / b;  // 除算
a = a ** b; // べき乗
a = a % b;  // 剰余
論理演算子には、論理積、論理和、論理否定があります。次の例は、これらの演算子の使用方法を示しています。
var a: bool = true, b: bool = false;
a = a && b; // 論理積
a = a || b; // 論理和
a = !a;     // 論理否定
関係演算子には、大なり、大なりまたは等しい、小なり、小なりまたは等しい、等しい、異なるが含まれています。次の例は、これらの演算子の使用方法を示しています。
var a: int = 1234, b: int = 5678;
a > b;  // 大なり
a >= b; // 大なりまたは等しい
a < b;  // 小なり
a <= b; // 小なりまたは等しい
a != b; // 異なる
a == b; // 等しい
ビット演算子には、左シフト、右シフト、ビット否定、ビット排他的論理和が含まれています。次の例は、これらの演算子の使用方法を示しています。
var a: int = 1234;
a << 10; // 左シフト
a >> 5;  // 右シフト
~a;      // ビット否定
a ^ b;   // ビット排他的論理和
複合代入演算子には、加算代入、乗算代入、除算代入、べき乗代入、左シフト代入、右シフト代入が含まれています。次の例は、これらの演算子の使用方法を示しています。
var a: int = 1234;
a += 10; // 加算代入
a *= 5;  // 乗算代入
a /= 2;  // 除算代入
a **= 3; // べき乗代入
a <<= 1; // 左シフト代入
a >>= 1; // 右シフト代入
交換演算子には、値の交換を行う```<=>`演算子が含まれています。次の例は、この演算子の使用方法を示しています。
var a: int = 1234, b: int = 5678;
a <=> b; // aとbの値を交換する
{{コラム|インクリメント・デクリメント演算子はありません|2=C言語ファミリー言語とは異なり、Chapelには前置/後置インクリメント/デクリメント演算子はありません。
n += 1およびn += 1はあります。
Rubyも、インクリメント・デクリメント演算子はありませんが、Rubyの場合はNumericはイミュータブルなのが理由で、若干事情が異なります。
Chapelも、多くのプログラミング言語と同じく、分岐と反復の制御構造を持ちます。
Chapelには、ifとselectの2つの分岐構文があります。
ifは、条件式に基づき分岐し、分岐先を評価します。
ifの値は、分岐先の式の値です。
var i = 0;
if i == 0 then
  writeln("零");
else
  writeln("非零");
    
if i == 0 {
  writeln("== 0");
} else {
  writeln("!= 0");
}
var s = if i == 0 then "ゼロ" else "非ゼロ";
writeln(s);
var q = 0.0 / 0.0;
if q == 0.0 then
  writeln("zero");
else if q < 0.0 then
  writeln("negative");
else if q < 0.0 then
  writeln("positive");
else
  writeln(q);
実行結果:
零
== 0
ゼロ
nan
if は、値を返すのでif文ではなくif式とも言えますが、値を使わない場合はelseを省略できます。
値を使うにelseを省略すると Syntax error となります。
構文(EBNF):
条件文 ::= "if" 条件式 "then" 文  [ "else" 文 ]
         | "if" 条件式 ブロック文 [ "else" 文 ]
         | "if" 制御変数宣言 "then" 文  [ "else" 文 ]
         | "if" 制御変数宣言 ブロック文 [ "else" 文 ]
ブロック文 ::= "{" 文 { 文 } "}"
制御変数宣言 ::= "var" 識別子 "=" 式
               | "const" 識別子 "=" 式
thenが突く場合とブロック文が続く場合があり、then を使うとPythonの様なインデント記法に見えますが、インデントは見栄えだけのものです。
select は、１つの式を評価してそれと一致する条件に対応する文を実行します。
var x = 4;
select x {
    when 0 do writeln("zero");
    when 1 do writeln("one");
    when 2, 3, 4, 5, 6, 7, 8, 9, 10 {
	writeln("two to ten");
	}
    otherwise 
	writeln("something else");
}
実行結果:
two to ten
構文(EBNF):
select文 ::= "select" 式 { when文列 }
when文列 ::= when文
           | when文 when文列
when文 = "when" 式リスト "do" 文
       | "when" 式リスト block-文
       | "otherwise" 文
       | "otherwise" "do" 文
式リスト = 式
         | 式 "," 式リスト
when の式リストには、範囲やパターンマッチングは書けないので、使い勝手はよくありませんので、多くの場合はifやマッピングを使うことになるでしょう。
また、列挙型( enum )とselect文を組み合わせて使うと、コードがより明確になります。この場合は、ifよりも好ましい選択です。
while-do文は、式が真である場合、続く文あるいはブロック文を繰り返します。
var i = 0;
while i < 5 {
    writeln("i = ", i);
    i += 1;
}
実行結果:
i = 0
i = 1
i = 2
i = 3
i = 4
このコードは、変数 i を 0 に初期化し、変数 i が 5 未満である間、次の処理を繰り返します。
変数 i の値を出力します。
変数 i に 1 を加算します。
このコードは、0 から 4 までの数字を出力します。
whileはfor系に比べて使い所が少ないですが、ファイル読み込みが典型的です。
file-read.chpl:
use FileSystem;
use IO;
proc main() {
  const f = open("/etc/passwd", ioMode.r);
  defer { f.close(); }
  const r = f.reader();
  defer { r.close(); }
  var line:string;
  while r.readLine(line) do
    write(line);
}
use FileSystem; と use IO; は、ファイルシステムと入出力操作を利用するモジュールをインポートします。
proc main() は、メインプロシージャです。
const f = open("/etc/passwd", ioMode.r); は、ファイル /etc/passwd を開きます。ファイルモードは ioMode.r で、読み取り専用です。
defer { f.close(); } は、ファイル f をクローズするデストラクターを記述しています。
const r = f.reader(); は、ファイル f のリーダを取得します。
defer { r.close(); } は、リーダ r をクローズするデストラクターを記述しています。
var line:string; は、行を格納する変数です。
while r.readLine(line) do は、リーダ r から行を読み込み、変数 line に格納します。このループは、リーダ r から読み取れる行がある間、継続します。
write(line); は、行 line を出力します。
このコードは、ファイル /etc/passwd の内容を読み込み、標準出力に表示します。
構文(EBNF):
while-do文 ::= "while" 式 "do" 文
             | "while" 式 ブロック文
             | "while" 制御変数宣言 "do" 文
             | "while" 制御変数宣言 ブロック文
do-while文は、文あるいはブロック文をまず実行し、式が真であれば繰り返します。
var i = 0;
do {
    writeln("i = ", i);
    i += 1;
} while i > 5;
実行結果:
i = 0
このコードは、変数 i を0で初期化し、ループの前に条件を評価しないdo-whileループです。
ループ内の処理は、writeln("i = ", i); という文で、i の値を表示します。
また、i += 1; の文により、i の値が1増えます。
ループの条件式は i > 5 ですが、最初の評価時点では i の値は1です。そのため、条件 i > 5 は成り立たず、ループは1回だけ実行されます。
構文(EBNF):
do-while文 ::= "do" 文 "while" 式
forループは範囲（range）、ドメイン（domain）、配列（array）、イテレータ（iterator）、または反復可能な任意のクラスを反復処理します。
var ary = [ 2, 3, 5, 7 , 11];
writeln("Apply for loop to ", ary);
for i in ary do
  write(i * i, " ");
var rng = 23 .. 31;
writeln("\n\nApply for loop to ", rng);
for i in rng do
  write(2**i, " ");
writeln();
実行結果:
Apply for loop to 2 3 5 7 11
4 9 25 49 121 
Apply for loop to 23..31
8388608 16777216 33554432 67108864 134217728 268435456 536870912 1073741824 2147483648 
1つ目のコードでは、var ary = [2, 3, 5, 7, 11]; という行で、配列 ary を定義しています。この配列には、2、3、5、7、11という数値が格納されています。
その後、Apply for loop to [2, 3, 5, 7, 11] という行で、forループを配列 ary に適用することを示しています。
ループの中では、各要素を変数 i に代入し、その要素の2乗を計算して表示しています。具体的には、i * i を計算して結果を表示しています。
2つ目のコードでは、var rng = 23 .. 31; という行で、範囲 23 .. 31 を定義しています。この範囲には、23から31までの整数が含まれています。
その後、Apply for loop to 23 .. 31 という行で、forループを範囲 rng に適用することを示しています。
ループの中では、範囲内の各値を変数 i に代入し、その値の2の累乗を計算して表示しています。具体的には、2 ** i を計算して結果を表示しています。
構文(EBNF):
for文 ::= "for" インデックス変数宣言 "in" 反復可能式 "do" 文
        | "for" インデックス変数宣言 "in" 反復可能式 ブロック文
        | "for" 反復可能式 "do" 文
        | "for" 反復可能式 ブロック文
インデックス変数宣言 ::= 識別子
                       | タプルでグループ化された識別子のリスト
反復可能式 ::= 式
             | "zip" "(" 式リスト ")"
キーワードzipを使用して複数の反復対象式をループ内でトラバースする場合、各反復対象が生成する対応する式は、ループのインデックス変数であるタプルとして結合されます。これを連結反復処理と呼びます。
zip()式の最初の反復対象は、ループの反復をリードし、反復空間のサイズと形状を決定します。その後の式はリード反復対象に従います。
これらのフォロワー反復対象は、リード反復対象によって生成される値の数と形状に適合することが期待されます。
たとえば、最初の反復対象がm行n列の2次元配列である場合、後続の反復対象も2次元m×n空間での反復をサポートする必要があります。
for (i, j) in zip(1..3, 4..8 by 2) do
  write(i, ":", j, ", ");
実行結果:
1:4, 2:6, 3:8, 
パラメータ付きforループでは、インデックス変数が変数ではなくパラメータとして展開されます。
構文(EBNF):
パラメータ付きfor文 ::= "for" "param" 識別子 "in" パラメータ反復可能式 "do" 文
                      | "for" "param" 識別子 "in" パラメータ反復可能式 ブロック文
パラメータ反復可能式 ::= 範囲リテラル
                       | 範囲リテラル "by" 整数リテラル
break文は、含まれるループから抜け出し、直後の文で実行を再開します。
continue文は、含まれるループの本体の末尾にジャンプし、そこから実行を再開します。
label文は、breakとcontinueがよりネストされていないループを終了または再開できるように、特定のループに名前を付けるために使用されます。ラベルは、for-、while-do、do-while文にのみ付けることができます。
break文にラベルがあると、そのラベルに対応するループ文に続く最初の文から実行が継続されます。
continue文にラベルがある場合、一致するラベルを持つループ文の本文の終わりで実行が継続される。
一致するラベルを持つループ文が存在しない場合、コンパイル時エラーが発生します。
並列処理を制御構造に１つに含めるのは奇異に感じられるかもしれません。
ここでは、for文の構文の延長にある forall cofaorall と foreach について扱います。
forallループは範囲（range）、ドメイン（domain）、配列（array）、イテレータ（iterator）、または反復可能な任意のクラスを反復処理します。
ここまでは、forループと同じですが、forループが単一のタスクによって直列に実行されるのに対し、forallループは任意の数のタスクを使用してループを実行することができます。
その結果、単一のタスクを使用して直列に実行される場合もありますし、反復の数に応じて任意の数のタスクを使用することもできます
var D = {1..1024};
var ary: [D] int;
forall i in D do
  ary[i] = i;
var sum = 0;
for i in D do
  sum += ary[i];
writeln("sum = ", sum);
実行結果:
sum = 524800
最初のループは、配列の要素にインデックスを代入しています。この処理は並列化できるのでforallが使えます。
二番目のループは、配列の要素の合計を求めていますが、前の要素までの小計がわかるまでは計算にかかれないので、forallは使えずforでシリアルに処理しています。
coforall文は、関連する同種のタスクを任意の数作成するために使用できます。構文的には、forループ文と似ていますが、forの代わりにcoforallキーワードを使用します。
動作上、coforallループは、ループの各反復ごとに独立したタスクを作成し、それぞれがループ本体のコピーを実行します。助記的には、coforallループはconcurrent forallと考えることができます。つまり、各反復が並行タスクである並列ループです。
cobegin文と同様に、元のタスクは、coforallの反復に対応する子タスクが完了するまで進行しません。そして、cobeginと同様に、元のタスクはその直接の子供だけを待ちます。子孫は待ちません。
foreachループは、ループの反復が順序に依存しないことを示します。
これにより、コンパイラはループをベクトル化したり、実行をGPUにオフロードしたりすることができます。
対照的に、forループは順序に依存し、forallループはイテレータに基づいて並列タスクを作成し、反復を分散することができます。
 を使って定義します。
proc.chpl:
proc ipow(base: int, times: int) : int
{
    if times < 0 then
        halt("invalid");
    var result = 1;
    var i = 0;
    while i < times {
        result *= base;
        i += 1;
    }
    return result;
}
proc main() {
    writeln("ipow(2, 0) = ", ipow(2, 0));
    writeln("ipow(2, 1) = ", ipow(2, 1));
    writeln("ipow(2, 2) = ", ipow(2, 2));
    writeln("ipow(2, 3) = ", ipow(2, 3));
    writeln("ipow(10, 4) = ", ipow(10, 4));
    writeln("ipow(2, -1) = ", ipow(2, -1));
}
実行結果:
ipow(2, 0) = 1
ipow(2, 1) = 2
ipow(2, 2) = 4
ipow(2, 3) = 8
ipow(10, 4) = 10000
proc.chpl:4: error: halt reached - invalid
recursive.chpl:
proc ipow(base: int, times: int) : int
{
    if times < 0 then
        halt("invalid");
    else if  times == 0 then
	    return 1;
    else if  times == 1 then
	    return base;
    return base * ipow(base, times - 1);
}
proc main() {
    writeln("ipow(2, 0) = ", ipow(2, 0));
    writeln("ipow(2, 1) = ", ipow(2, 1));
    writeln("ipow(2, 2) = ", ipow(2, 2));
    writeln("ipow(2, 3) = ", ipow(2, 3));
    writeln("ipow(10, 4) = ", ipow(10, 4));
    writeln("ipow(2, -1) = ", ipow(2, -1));
}
say_hello.chpl:
proc say_hello(who: string = "World")
{
    writeln("Hello ", who, "!");
}
proc main() {
    say_hello();
    say_hello("Universe");
}
実行結果:
Hello World!
Hello Universe!
varargs.chpl:
proc sum(args: int ...?n) : int
{
    writeln("<", args.type:string, ">");
    var result = args(0);
    for i in 1..
実行結果:
arg1 = 123, arg2 = abc
arg1 = 256, arg2 = XYZ
arg1 = 0, arg2 = Zero
 を使って定義します。
{{コラム|関数宣言キーワード|2=Chapel-1.4（2011年10月）より前では、プロシージャとイテレータの両方を定義するためにdefを使用していました。
コンパイラは、関数本体にyieldステートメントが存在するかどうかを検査することで、プロシージャかイテレータかを判断していました。
1.4の変更により、これらの2つのケースを明確に区別するために、キーワードprocとiterを導入しました。
この変更により、誤りを防ぎ、それぞれのケースを明確に区別するセマンティクスをサポートし、インターフェースの指定をより良くサポートすることができるようになりました。
// イテレータの定義
iter MyIterator(start: int, end: int): int {
  var current = start;
  // イテレーション本体
  while current <= end {
    yield current;
    current += 1;
  }
}
// イテレータの使用
var myIter = MyIterator(1, 5);
for i in myIter do
  writeln("i = ", i);
実行結果:
i = 1
i = 2
i = 3
i = 4
i = 5
この例では、MyIteratorというイテレータを定義しています。イテレータは、startからendまでの整数を順に生成します。
MyIteratorの定義では、iterキーワードを使用してイテレータを宣言しています。イテレータの本体はwhileループで構成されており、currentの値をイテレータとして返すたびに、yieldステートメントを使用してその値を生成します。そして、currentを1増やし、次の値を生成するための準備をします。
イテレータを使用するために、MyIteratorを呼び出してmyIterという変数に代入しています。その後、forループを使用して、myIterからイテレータが生成する値を順番に取得し、writeln関数を使って出力しています。
基本的なアルゴリズムが共有する手続きとイテレータを比較してみましょう。
素数のリストを返す手続き:
proc get_primes(n: int){
  use List;
  var primes = new list(int);
  for i in 2..n {
    var flag = true;
    for prime in primes {
      if i % prime == 0 {
        flag = false;
        break;
      }
    }
    if flag {
      primes.append(i);
    } 
  }
  return primes;
}
var p = get_primes(100);
writeln([i in p] i);
実行結果:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97
：* このアルゴリズムの主役は、primesというリストです。
：* primes は名前の通り素数のリストで、その中に因数がない数が素数で primes 自身に追加します。
素数を順に返すイテレータ:
iter gen_primes() {
  use List;
  var primes = new list(int);
  for i in (2..) {
    var flag = true;
    for prime in primes {
      if i % prime == 0 {
        flag = false;
        break;
      }
    }
    if flag {
      primes.append(i);
      yield i;
    }
  }
}
var p: [1..100] int;
for (i, j) in zip(gen_primes(), 1..) {
  if j > p.size then 
    break;
  p[j] = i;
}
writeln([i in p] i);
実行結果:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 101 103 107 109 113 127 131 137 139 149 151 157 163 167 173 179 181 191 193 197 199 211 223 227 229 233 239 241 251 257 263 269 271 277 281 283 293 307 311 313 317 331 337 347 349 353 359 367 373 379 383 389 397 401 409 419 421 431 433 439 443 449 457 461 463 467 479 487 491 499 503 509 521 523 541
：* このアルゴリズムの主役は、primesというリストです。
：* primes は名前の通り素数のリストで、その中に因数がない数が素数で primes 自身に追加します。
素数を順に返すイテレータ（別解）:
iter primegen() {
  var n = 2;
  var D: domain(int); // empty set of integer
  var sieve: [D] int;
  while true {
    if !D.contains(n) || sieve[n] == 0 {
      yield n;
      D += n * n;
      sieve[n * n] = n;
    } else {
      var factor = sieve[n];
      D += n + factor;
      sieve[n + factor] = factor;
      sieve[n] = 0;
    }
  n += 1;
  }
}
proc main() {
  for prime in primegen() {
    write(prime, " ");
    if prime > 50 then break;
  }
  writeln();
}
実行結果:
2 3 5 7 11 13 15 17 19 21 23 27 29 31 33 35 37 39 41 43 45 47 51 
 を使って定義します。
演算子メソッドは、Chapelで演算子の振る舞いを定義するために使用されます。これにより、特定の型に対して演算子をオーバーロードすることができます。
演算子メソッドは、次の構文で定義されます。
 
operator (lhs: T, rhs: T): T {
  // 演算子の振る舞いを定義するコード
  // ...
  return result; // 演算結果を返す
}
上記の構文で、は演算子を表すシンボル（例: +, -, *, /）を指定します。lhsとrhsは同じ型Tの引数であり、演算子の左辺と右辺の値を表します。
operator (lhs: T, rhs: T): T {
  // 演算子の振る舞いを定義するコード
  // ...
  return result; // 演算結果を返す
}
record Point {
  var x: int;
  var y: int;
  // 和
  operator +(lhs: Point, rhs: Point) do
    return new Point(lhs.x + rhs.x, lhs.y + rhs.y);
  // 差
  operator -(lhs: Point, rhs: Point) do
    return new Point(lhs.x - rhs.x, lhs.y - rhs.y);
  inline operator :(pt: Point, type t: string) {
    if pt.y >= 0 then 
      return "Point(" + pt.x:string + " + " + pt.y:string + ")";
    else
      return "Point(" + pt.x:string + " - " + (-pt.y):string + ")";
  }
}
var p1 = new Point(2, 3);
var p2 = new Point(4, 1);
writeln(p1:string," + ",  p2:string, " = ", (p1 + p2):string);
writeln(p1:string," - ",  p2:string, " = ", (p1 - p2):string);
operator Point.+(lhs: Point, rhs: int) do
    return new Point(lhs.x + rhs, lhs.y + rhs);
writeln(p1:string," + ",  2, " = ", (p1 + 2):string);
実行結果:
Point(2 + 3) + Point(4 + 1) = Point(6 + 4)
Point(2 + 3) - Point(4 + 1) = Point(-2 + 2)
Point(2 + 3) + 2 = Point(4 + 5)
レコード型 Point を定義し、+ 演算子と - 演算子をオーバーロードしています。また、キャスト演算子 : も定義しています。
まず、和と差の演算子メソッドを定義しています。+ 演算子メソッドでは、2つの Point オブジェクトの x と y の値をそれぞれ足し合わせた新しい Point オブジェクトを返します。同様に、- 演算子メソッドでは、2つの Point オブジェクトの x と y の値をそれぞれ引き算した新しい Point オブジェクトを返します。
次に、キャスト演算子 : を定義しています。これは Point オブジェクトを他の型に変換するための演算子です。例えば、Point(2 + 3) のような形式の文字列を返します。ただし、y の値が負の場合は - を使って表現します。
モジュールはコードのグループ化であり、各プログラムは少なくとも1つのモジュールから構成され、すべてのシンボルはあるモジュールに関連付けられます。
ファイルのすべてのコードがmoduleキーワードを使用して明示的なモジュールで囲まれていない場合、ファイル自体はファイル名（.chpl拡張子を除く）と同じ名前のモジュールとして扱われます。
コンパイラは、コマンドラインでモジュールの名前を指定するか、-Mフラグに依存することで、異なるファイルにモジュールを含めるように指示することができます。
module M1 {
  var x = 10;
  var y = 20; // 3: error: symbol y is multiply defined
}
module M2 {
  var y = 30; // 7: note: also defined here
}
module Main {
  use M1;
  use M2;
  proc main() {
    writeln("M1.x = ", M1.x); 
    writeln("x = ", x); 
    writeln("M1.y = ", M1.y); 
    writeln("M2.y = ", M2.y); 
//    writeln("y = ", y); 
  }
}
M1.x = 10
x = 10
M1.y = 20
M2.y = 30
複数のモジュールを持つプログラムでは、モジュールが他のモジュールの内容にアクセスすることが一般的です。そのための出発点は、Chapelのuse文またはimport文です。これらの文は、実行可能なコードを含む任意のレキシカルスコープに挿入することができます。
デフォルトでは、use文は特定のモジュールのすべての可視シンボルを、そのuse文を含むスコープで利用可能にします。これらのシンボルは、モジュール名の接頭辞なしで直接アクセスすることができます。
module M3 {
  var x = 10;
  var y = 42;
}
module M4 {
  private var y = 100;
}
module Main {
  use M3, M4;
  proc main() {
    writeln("M3.x = ", M3.x); 
    writeln("x = ", x); 
    writeln("M3.y = ", M3.y);
    writeln("y = ", y); 
//    writeln("M4.y = ", M4.y); error: Cannot access 'y', 'y' is private to 'M4'
  }
}
M3.x = 10
x = 10
M3.y = 42
y = 42
module M5 {
  var x = 10;
}
module M6 {
  var y = 42;
}
module M7 {
  var z = 123;
}
module Main {
  proc main() {
    import M5;
    writeln("M5.x = ", M5.x); 
//    writeln("x = ", x); error: 'x' undeclared (first use this function)
	import M6.y;
//    writeln("M6.y = ", M6.y); error: 'M6' undeclared (first use this function)
    writeln("y = ", y); 
	import M7.z as a;
//    writeln("M7.z = ", M7.z); error: 'M7' undeclared (first use this function)
//    writeln("z = ", z); error: 'z' undeclared (first use this function)
    writeln("a = ", a); 
  }
}
M5.x = 10
y = 42
a = 123
module M8 {
  var x = 10;
}
module Main {
  proc main() {
    {
        use M8 as xyz;
//        writeln("M8.x = ", M8.x); error: 'M8' undeclared (first use this function)
        writeln("xyz.x = ", xyz.x); 
        writeln("x = ", x);
    }
    {
        use M8 as _;
//        writeln("M8.x = ", M8.x); error: 'M8' undeclared (first use this function)
//        writeln("_.x = ", _.x); syntax error: near '_'
        writeln("x = ", x);
    }
  }
}
xyz.x = 10
x = 10
x = 10
Chapelにおける例外処理は、通常のプログラミング言語とは異なる独自の機構を持っています。
Chapelでは、並列処理をサポートするために非同期タスクと呼ばれる並列実行単位があります。
非同期タスク内で例外が発生した場合、その例外をキャッチするためのメカニズムが提供されています。
proc divide(a: int, b: int) throws
{
  if a == 0 && b == 0 {
    throw new DivisionError("Divide zero by zero.");
  }
  if b == 0 {
    throw new DivisionError("Division by zero");
  }
  return a / b;
}
class DivisionError: Error {
  var msg: string;
}
proc main() throws
{
  try {
    writeln(divide(10, 2));
    writeln(divide(0, 0));
    writeln(divide(10, 0));
  } catch (e: DivisionError) {
    writeln("Caught DivisionError: ", e.msg);
  }
}
この例では、divideという手続きがあります。この手続きは2つの整数を受け取り、いくつかの条件に基づいて除算を行います。条件に違反する場合、DivisionErrorという例外をスローします。
DivisionErrorは、Errorクラスを継承しており、msgというメッセージを保持するプロパティがあります。
main手続きでは、divide手続きを呼び出して結果を出力します。最初の呼び出しでは正常な除算が行われ、結果が表示されます。2番目の呼び出しでは、ゼロをゼロで除算するため、例外がスローされます。3番目の呼び出しではゼロで割るため、同様に例外がスローされます。
tryブロックで呼び出しを囲み、例外をキャッチするためのcatchブロックがあります。catchブロックでは、DivisionErrorのインスタンスをキャッチして、エラーメッセージを表示します。
この例では、throwsキーワードを使用して手続きとメイン関数のシグネチャに例外の可能性を示しています。これにより、例外が発生する可能性がある処理を明示的に示すことができます。
Chapelでは、ジェネリックプログラミングのサポートがあります。
ジェネリックプログラミングは、異なるデータ型に対して汎用的なアルゴリズムやデータ構造を定義するためのテクニックです。
Chapelでは、型パラメータを使用してジェネリックなコードを記述することができます。
[https://ato.pxeger.com/run?1=pVS7SgNBFG2spvMPLlZZ3GzMU80SK1tBUGyWFEMyIYub3WV3YhQRJFtYiJ3a2ATBBzZaWvj4D9sJSv7CO_tIsmK31XDvPefMuWdgbu5bXeoyazS66_NOfu1rYbFQADF8FcMHEVyI4EkEgRg-T65vv69eiOs5LeiYdnuLHuaod6QcE4AD6sEmNABrre30qGnrcbdHD_eoFY2MTc1yBk056jgemJz1wLRnk-WipjWh7eAcwOxEgI1EgneZHU5gJioRUs5jvO_ZcV8nJ4T8u4IIzkTwJoaf3w_nk9MRaVnU92GH09Y-yDX4kcuAWXwXz2QBeYVfBwO9laq15t8xd9w6LsHRzIpOsBnm4_b9bk4y6wleCS8AiYflBhT1aEkpbmCvObfMyUzGcXMJMfESAyOWPtXMTzXjLGZqURrj98-fy8fxxzmRSpg5ChllFVZVKKmwrkIV1QYe0iw7t4SPizdafVaHJTX13IoOqNbYgDnIOglF_TDIBthsEIVqYDCoGva1MJOikipL6bKszFnYdlyXtSFKEU3EOBnJ1EMKU87ALc3bqKRdVdNlLZPJWgZuNQO3koFbJNHPEH8QyUfxCw ジェネリック関数とジェネリックデータ構造]:
// ジェネリック関数
proc findMax(ary){
  var D = ary.domain;
  var maxVal = ary[D.low];
  for item in ary[D.low+1..] do
    if item > maxVal then
      maxVal = item;
  return maxVal;
}
// ジェネリックデータ構造
class Stack {
  type eltType;
  var items: [1..256] eltType;
  var top: int = 0;
  proc push(item: eltType) {
    top += 1;
    items[top] = item;
  }
  proc pop() {
    var item = items[top];
    top -= 1;
    return item;
  }
}
// 使用例
var ary = [3, 7, 2, 9, 5];
writeln("Max value: ", findMax(ary)); // => Max value: 9
var stack = new Stack[int];
stack.push(1);
stack.push(2);
stack.push(3);
writeln("Popped item: ", stack.pop()); // => Popped item: 3
writeln("Popped item: ", stack.pop()); // => Popped item: 2
stack.push(4);
stack.push(5);
stack.push(6);
writeln("Popped item: ", stack.pop()); // => Popped item: 6
writeln("Popped item: ", stack.pop()); // => Popped item: 5
writeln("Popped item: ", stack.pop()); // => Popped item: 4
writeln("Popped item: ", stack.pop()); // => Popped item: 1
このプログラムは、ジェネリック関数とジェネリックデータ構造を使用しています。
まず、findMaxという名前のジェネリック関数が定義されています。この関数は、配列aryの要素の中から最大値を見つけるためのものです。aryの最初の要素を初期の最大値maxValとして設定し、aryの2番目以降の要素についてループを行います。各要素がmaxValよりも大きい場合、maxValを更新します。最終的に、maxValを返します。
次に、Stackという名前のジェネリックデータ構造が定義されています。このデータ構造は、ジェネリックな要素の配列itemsと、トップの位置を示す整数topを持っています。pushプロシージャは、itemをitemsの次の位置に追加し、topをインクリメントします。popプロシージャは、topの位置から要素を取り出し、topをデクリメントしてからその要素を返します。
最後に、このプログラムではこれらのジェネリック関数とジェネリックデータ構造が使用されています。
まず、整数型の配列aryrが定義されています。この配列は[3, 7, 2, 9, 5]という要素を持ちます。findMax関数を使用してaryの最大値を見つけ、writeln関数を使用して結果を表示します。
次に、Stackデータ構造のインスタンスstackが作成されます。stack.pushメソッドを使用して、要素1、2、3をstackに追加します。stack.popメソッドを使用して要素を取り出し、結果を表示します。stack.pushメソッドとstack.popメソッドをさらに使用し、要素4、5、6を追加・取り出し、結果を表示します。
エラトステネスの篩を、若干 Chapel らしく書いてみました。
[https://ato.pxeger.com/run?1=fVNdTxNREH3wbX_FPG4bXGoTE9OGX0KILWUbblLv1t0Fo8ZkP0AKtAmpYEMhWmOtRZLWCCbWgPwPX4fb4hN_wbl3uy1i9D7sTnbPzJw5Z-5Bp7CcL5ulVuvDilu8--DnHW92FnKmnXctx102uenkAP0-ej56VQy6GB5hWMFggOFLDGsy8Huj_hF6FNcvzy9Gu130G-h3KCVNqdsYbEKOyyo_0P8o0aet4d5nCjD8pApRufrVxa5KI8w-eoFWtq0C3KSh8www7ibguQYgOTrMXDVjcv_o1F8TB18oEF6bemDQxvAEww0MQwz6intX9gu2f63XRKWhslR71QL9VxhU_9dAov2BHDYeS3j7V-8P5UDvYh38telYqu4tpFgnZGfYPBa95qhJ4OPR4VvFrHEzcTVvg5o5A_Npw-ALsGhZJZgD114xsxohChZ3XHAe2-5DTt8LJivpHJJJSBn3E1lQh9qPAdFc8t0Tg5Ph68GwNbg-q4jKBgZbl9-20K9fn21S2aJlAyPtgbpGuRkyApYsmB5NPlgxIjjPFkCaBn-diW8EkTJW1aQ90ToVOxVik2PK0HhDSOKAzInmlyfKTUOSCBkGcFh8CtRsDor5kmNmp-JOciEqSRtQk59jtYV_PvFelh8b83Vn-GZs3qj9_ZYBT2zmmiWuSz308gywhBTlGSvritZMxM5Ysh7lGU9IfUiQcqQES2S1F1q01fK3Hu3xHwt-L5WSqOgiju9jfC9_Aw エラトステネスの篩]:
// `eratosthenes` は、「エラトステネスの篩」を使用して、2 から `n` までの素数のリストを返します。
proc eratosthenes(n: int) {
  // `sieve` は、2 から `n` までの範囲の値をインデックスとする配列です。
  // これは、2 から `n` までのすべての素数候補を表しています。
  // 素数候補を全て暫定的に真とします。
  var sieve: [2..n] bool = true;
  const sqrt_n = ceil(n ** 0.5);      // sqrt_n は、n の平方根（切り上げ）
  for i in 2..sqrt_n:int do           
    if sieve[i] then                  // `sieve[i]` が真の場合、`i` は素数である。
      sieve[2 * i .. n by i] = false; // 素数である `i` の倍数を全て偽とする。
  // 結果を表示します。
  writeln(for (p, i) in zip(sieve, sieve.domain) do if p then i);
}
proc main() {
  eratosthenes(100);
}
実行結果:
2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 83 89 97 
クイックソートを、若干 Chapel らしく書いてみました。
[https://ato.pxeger.com/run?1=dVLLTsJAFE1c8hUnrNowVMEX8tD4BSa6rF00pdBbSweHAUIMX-KGjX6UX-OdMlMFYzKLmXPPOfcx9_0zyeJ5Wux2H0s9afe-Th7nSiZ4XVLyspBKe7Ha9BHejeUs8vHWAFaxAmEERoJCrgcWyi2U0TQzWCLLhcacVlJzhF1CzyrQqok-TtGNDJ3POqMiZevhiM1MJgcZMUUYWrexrGJgamuEzqB6HdHzCLfH9BztQzpNXDadpaVleftswtoIkEDucwueAxyB06MjjC06vrHd7vtgW9fp8Lf3wUxDSwmCPPIHtZDrqYfzn5KCwFGMdNtoVF82i6n0fr6ImVx0eCNwKXAt0BW4EKbensA5X84ErurJK9JpUXrNB0VTKuMC90rFm_6zblbtugIP6vCPxU8cSMd_pdv9atkNc5v2DQ クイックソート]:
proc quicksort(ary: [?dom]) {
  var i = dom.low;
  var j = dom.high;
  const pivot = ary[(dom.low + dom.high) / 2];
  
  while i <= j {
    while ary[i] < pivot do
      i += 1;
    
    while ary[j] > pivot do
      j -= 1;
    
    if i <= j then
      (ary[i], ary[j], i, j) = (ary[j], ary[i], i + 1, j - 1);
  }
  
  if dom.low < j then
    quicksort(ary[dom.low..j]);
  
  if i < dom.high then
    quicksort(ary[i..dom.high]);
}
proc main() {
  var ary = [9, 5, 7, 2, 4, 1, 8, 3, 10, 6];
  
  writeln("Original Array:\t", ary);
  
  quicksort(ary);
  
  writeln("Sorted Array:\t", ary);
}
実行結果:
Original Array:	9 5 7 2 4 1 8 3 10 6
Sorted Array:	1 2 3 4 5 6 7 8 9 10
proc quicksort(ary: [?dom]) {のary: [?dom]が特徴的で、配列を渡すと、ドメイン（添字範囲）も暗黙に渡ります。
これは再帰でも応用されquicksort(ary[dom.low..j]);のように部分配列を意味どおりに表現しています。
最大公約数と最小公倍数を、若干 Chapel らしく書いてみました。
[https://ato.pxeger.com/run?1=rVRRS9tQFH7Zy_IrDsIgkbu01oli1-23lJpqILmVNJ0PQ-htOrY9DDchijiYSO1kkyooCLX46n_Y6zF1_Rc7uTeZmdtqB4OQe--53znn-84Hd7dbWSmvWs7e3kHDrz5e-PbgKpeD5cpSAVAcY1PEawdFbxieDcMTcOl4CBziyMdm1PkcvTq6OWvTFbY2vx--uelto6DvEsUONlsaFbOrhC-VIA_-isWpguXULdlC54yOj4AbSTMMuhgMsHWMwRcMAgzeUp_r_uZopzM8DVF8jT71URygaKPoju3flZiUxapXq6iO7iLY3GfA5WrIPyzVwLP8hscn4lrUNDWihPT1xcWwvUFER-E5ivDnrGgTDUK1mWhWKUu97C3XFTPTNJ_zhOVLDeBF2SOq9YbjQwlimJ4nPgDVmgc2oWDGNJ9yEkQxuEVKAerEVJptyLxEtroqautSmlNxJ3P_ZIMURc1349x3YZoScsn02a3XYwv8wb6Y1X32_d6smCr6R7PulZZy-v9mSaETm-WWbZ5oi1WzWDuTNVgiuxe9b4-29pWS6MMAxWn0uv-3Mcf1dEPyB1jzbN9yuD4lBzqbZ_BkzoDSM5hikA0RvYdZrIzPE4OZQgaejf6SIRWryxSeDd3Fqq6FO_BslDLW1XuWPGvp8_YD 最大公約数と最小公倍数]:
// gcd2 は、2 つの整数 m と n の最大公約数を計算します。
// if n == 0 then m else gcd2(n, m % n) は、ユークリッドの互除法に基づいて最大公約数を計算しています。
proc gcd2(m: int, n: int): int do return if n == 0 then m else gcd2(n, m % n);
// gcd は、任意の長さの整数の引数の最大公約数を計算します。
proc gcd(args: int ...?n): int {
  var result = args(0);
  for i in 1.. ", gcd2(30, 45));
	writeln("gcd(30, 72, 12) => ", gcd(30, 72, 12));
	writeln("lcm2(30, 72) => ", lcm2(30, 72));
	writeln("lcm(30, 42, 72) => ", lcm(30, 42, 72));
}
実行結果:
gcd2(30, 45) => 15
gcd(30, 72, 12) => 6
lcm2(30, 72) => 360
lcm(30, 42, 72) => 2520
二分法を、若干 Chapel らしく書いてみました。
[https://ato.pxeger.com/run?1=tZTdThpBFMdvesVTnGia7FY-25tG9Kqv0cQg2ZVNKBjAugkhYXeJRdGoRDCKicSikhKQCBfUGH2P3g7DYvoSPTO7LB8lbW-6F_sxe87vf-Y_Z6ZyE46ENqVotXq9lZI973-8-unzwbqSlMIpJR4Dot2RrPZSvhqU2iDj5z748d4wm7tEOyXaIdG-Eb1AW5csQAWiF_sP-zS_M-iUiHY7qF2Y3Sse-US0M5LVXYiPxreRUYeIshH5XaFFszVbR88TfY-2UQRhOfMuRyv3GNDvFV7OjpDQ7-3xl9sxW7WB5uETvajz4Kapf5-KkdU5qjzT0h6Fbibi4bEXwhrWvQwJKRR1wxqrffQhLwMLFVRrQLQfYD0h7XIBoOwH7jTHM3H6WEJx9q7XiHFJjGtiPBL9mRhlYjSYr1qLBRtNPt7AQVrb5SkNoneIccLGJ60F-BxKcHdXgRXrthxetaoN2mXYhujFYT1vtk7nEFRMERhmiQNE8MHbUfaMV3-gyAwjC6ropLKsfXqgYXvgHJx1pdUuPcpbpvAOGj6fzPAUGYTQelKQVRFWYCng9UuegF-EVESK4W9Ao1NbiRioIy27V_TioNIdlNtzcFjNCvi9NmRc3_C-yuY2URNvV73IJ90Y1pu0dT7DA9t0lAeQokkJpi8HPmh-nYFbe-AvdHsZndnRnQPaa5vnOWbjMTZBh355YFn_sFWtTTq8KRANW_14Usg2cdzxTg9hj-MyZlzWlvgUUmKCiH0NsJ1QUpIsLLxOL3oXZ67Mx9iCe4Lmd8M797ydAmln_cADgSBkRDH4P-BvpgQyLuvMs4--0RH4Cw 二分法]:
// bisection は、関数 f が 0 に等しくなる実数 x を二分法で検索します。
// low と high は、関数 f の値が 0 より小さい範囲の下限と上限です。
// x は、現在の中点です。
// fx は、関数 f の x の値です。
proc bisection(_low: real, _high: real, f: proc(x: real): real) : real {
  // Chapelでは、引数はイミュータブルなのでローカル変数にコピーします。
  var low = _low, high = _high;
  // 中点を計算します。
  var x = (low + high) / 2;
  // f の x の値を計算します。
  var fx = f(x);
  // fx が十分に小さい場合は、x を返します。
  if (abs(fx) < +1.0e-10) then
    return x;
  // 範囲を更新します。
  if (fx < 0.0) then // fx が負の場合は、low を x に設定します。
    low = x;
  else               // fx が正の場合は、high を x に設定します。
    high = x;
  // 再帰的に呼び出し、関数 f が 0 に等しくなる x を見つけます。
  return bisection(low, high, f);
}
proc main() {
  writef("%{#.################}\n", bisection(0, 3, proc(x: real): real { return x - 1; }));
  writef("%{#.################}\n", bisection(0, 3, proc(x: real): real { return x * x - 1; }));
}
実行結果:
0.9999999999417923 
1.0000000000291038
旧課程(-2012年度)高等学校数学B/数値計算とコンピューター#2分法の例を Chapel に移植しました。
順列を、若干 Chapel らしく書いてみました。
[https://ato.pxeger.com/run?1=rVRLboMwEN10lVNMszItQTHtoiKKconuIhYkMYojYixjmiYRJ-kmm-ZQPU3HGBKgtFWlIvGxefPmvRnbb-flOpIsOZ3ecx2Pnj5uzlKlS5BMbXMdaZ4KkgUwn63SbQgzlujnvWQuiAC40E4AA-hcc-p5PAYB0ylQ0GsmAGO9jB8YsCRjEEdLnSoeJaSed1zAIBFCRQ_HkvUlUqBYlic6-A_WSUl6JTlepMepAqK4Cxl30BYcuCQ2sYdkERfeim_J2HGzauxg8rZxCy9JqANTyAhyTQbX3zpXokLZ6eLikVMM6MvnJenOgo1CbqTVClBAw4BhyfKFyTs30E0Xiq453E7xR1m6TThpxUqJoa2W5wvsMYzQzKRVJkkNtZRtoW01Neum3xdt-OqUj1MXo2z9muUzF7LdY9vak6Uk_6sk2iOpL42UROJA-p1k3-UrWiPehRSNznZaXgwG5ca6rtPLFsJnvZ6qoHqRjm27qF3iAu6a4VV3LK1xTpzK8U5xzRJBmh2d07ELPt4PeD-OQ_xwKtO9cERhYXzE-T_ihtFiOXRhuGKxeb3uD8NfuQ0xYkKzV_7OXcYU9riqTq369PoE 順列]:
proc permutation(s: [?dom] ?eltType, n: int): 
                [1..if n == 1 then dom.size else factorial(dom.size), 1..n] eltType {
    var result: [1..if n == 1 then dom.size else factorial(dom.size), 1..n] eltType;
    if n == 1 {
        for (ri, si) in zip(result.domain.dim(0),s.domain) do
             result(ri, 1) = s(si);
        return result;
    }
    var i1 = result.domain.dim(0).low;
    for i in s.domain do {
        var sub = s[for j in s.domain do if i != j then j];
        var pp = permutation(sub, n - 1);
        for p1 in pp.domain.dim(0) do {
            var j1 = result.domain.dim(1).low;
            result(i1, j1) = s(i);
            j1 += 1;
            for p2 in pp.domain.dim(1) do {
               result(i1, j1) = pp(p1, p2);
               j1 += 1;
            }
            i1 += 1;
        }
    }
    return result;
}
proc factorial(n: int): int do
    return if n == 0 then 1 else n * factorial(n - 1);
proc main() {
    writeln(permutation([10, 20, 30, 40], 3));
    writeln(permutation([0, 1, 2], 2));
    writeln(permutation(["abc", "def", "xyz"], 3));
    writeln(permutation([1, 2, 3], 1));
    writeln(permutation(["abc", "def", "xyz"], 1));
}
実行結果:
10 20 30
10 20 40
10 30 20
10 30 40
10 40 20
10 40 30
20 10 30
20 10 40
20 30 10
20 30 40
20 40 10
20 40 30
30 10 20
30 10 40
30 20 10
30 20 40
30 40 10
30 40 20
40 10 20
40 10 30
40 20 10
40 20 30
40 30 10
40 30 20
0 1
0 2
1 0
1 2
2 0
2 1
abc def xyz
abc xyz def
def abc xyz
def xyz abc
xyz abc def
xyz def abc
1
2
3
abc
def
xyz
proc permutation(s: [?dom] ?eltType, n: int): [1..if n == 1 then dom.size else factorial(dom.size), 1..n] eltType 戻値型は二次元配列で次元ごとの要素数が引数により変化するので関数を呼び出し決定しています。また n == 1 はfactorial()では求められないので、if式で切り替えています。
順列自身は再帰的な定義なので、定義どおりに再帰しています。
再帰関数は、戻値型が必須なので冒頭のやや複雑で動的な戻値型の定義が必要になります。
このコードはジェネリックプログラミングの例にもなっています。
組み合わせを、若干 Chapel らしく書いてみました。
[https://ato.pxeger.com/run?1=tVTBUsIwEL144it2OCVaKqkenDLIT3hjeiglHcKUNNOmIjD8g3cvXPSj_Bo3TQttrXqyMwUS3r59b3eTt49oFSqenE7vhY5HD59XrypLI4jSzULIUItUktyH-WyZbgKY8UQ_7RR3QPogpKY-DKDzzJnrihgkTKfAQK-4BIx1c7HnwJOcQxxGOs1EmJB6n8JtY1dSB5BDBlBlg0OZ5DnMION5kWj_H5JMyhwXzsPZWJxmQDLhQC4omoa9UMTqcJE7FNJdig0ZUyev1hS1tMti4SUJozCFnCDXZHD5WxeZrFB2-3i2LBgG9OVzk3RrwUahMNJqBSigYcCw5MXC5J0b6LoLRddreESKspDrYNIKVQojW_NQLHAAYIReJq0qKWaYlWrrbIupWdf9tljDVqd6gjkYZcvXrJ55kO0Gu9beLCV53yWxHkl9aZQiChfK6yT7Kd-xtRJdyLHR2E7Hj4NBeeoa81mfL_ysx6kKqmd0bNvF7MBLuG6GV92xtMY5oZXjbSY0TyRpdnTOxg54-N7hez8O8AetTPfCEYWF8RDn_Yobhoto6MBwyWPz9bLbD__kNsSICcxRoaY09mKq7qf6nvoC 組み合わせ]:
proc combination(s: [?dom] ?eltType, n: int): 
                [1..if n == 1 then dom.size else factorial(dom.size) / factorial(n), 1..n] eltType {
    var result: [1..if n == 1 then dom.size else factorial(dom.size) / factorial(n), 1..n] eltType;
    if n == 1 {
        for (ri, si) in zip(result.domain.dim(0),s.domain) do
             result(ri, 1) = s(si);
        return result;
    }
    var i1 = result.domain.dim(0).low;
    for i in s.domain do {
        var sub = s[for j in s.domain do if j > i then j];
        var pp = combination(sub, n - 1);
        for p1 in pp.domain.dim(0) do {
            var j1 = result.domain.dim(1).low;
            result(i1, j1) = s(i);
            j1 += 1;
            for p2 in pp.domain.dim(1) do {
               result(i1, j1) = pp(p1, p2);
               j1 += 1;
            }
            i1 += 1;
        }
    }
    return result;
}
proc factorial(n: int): int do
    return if n == 0 then 1 else n * factorial(n - 1);
proc main() {
    writeln(combination([10, 20, 30, 40], 3));
    writeln(combination([0, 1, 2], 2));
    writeln(combination(["abc", "def", "xyz"], 3));
    writeln(combination([1, 2, 3], 1));
}
実行結果:
10 20 30
10 20 40
10 30 40
20 30 40
0 1
0 2
1 2
abc def xyz
1
2
3
順列と同じく戻値型が複雑で動的です。
組み合わせ自身は再帰的な定義なので、定義どおりに再帰しています。
再帰関数は、戻値型が必須なので冒頭のやや複雑で動的な戻値型の定義が必要になります。
このコードもジェネリックプログラミングの例にもなっています。
Chapel-1.30 の構文です。
program ::= toplevel-statment-list
toplevel-statment-list ::= (* empty *)
                         | toplevel-statment-list toplevel-statment
toplevel-statment ::= statment
                     | pragma-list statment
pragma-list ::=             "pragma" STRINGLITERAL
              | pragma-list "pragma" STRINGLITERAL
statment ::= attribute-group attribute-receiver
           | statment-base
statment-base ::= tryable-statment
                | decl-base
                | include-module-statment
                | block-statment
                | use-statment
                | import-statment
                | require-statment
                | extern-block-statment
                | implements-statment
                | interface-statment
                | "defer" statment
                | try-statment
                | return-statment
                | "break" optional-label-ident ";"
                | "continue" optional-label-ident ";"
                | "label" ident-def statment
                | "yield" optional-try-expression ";"
                | error ";"
tryable-statment ::= assignment-statment
                   | if-statment
                   | loop-statment
                   | select-statment
                   | manage-statment
                   | statment-level-expression ";"
                   | throw-statment
                   | "begin" optional-task-intent-list statment
                   | "cobegin" optional-task-intent-list block-statment
                   | "delete" expression-list ";"
                   | "local" expression do-statment
                   | "local" do-statment
                   | "on" expression do-statment
                   | "serial"  expression do-statment
                   | "serial"  do-statment
                   | "sync"  statment
decl-base ::= module-declaration-statment
            | class-level-statment
attribute-receiver ::= loop-statment
                     | decl-base
                     | block-statment
attribute-group ::= attribute-declaration-statment-list
attribute-declaration-statment-list ::=                                     attribute-declaration-statment
                                      | attribute-declaration-statment-list attribute-declaration-statment
attribute-declaration-statment ::= attribute-declaration-begin optional-attribute-declaration-toolspace optional-attribute-actuals
                                 | attribute-declaration-begin optional-attribute-declaration-toolspace
                                 | attribute-declaration-begin STRINGLITERAL
attribute-declaration-begin ::= "@" TIDENT
optional-attribute-declaration-toolspace ::= (* empty *)
                                           | "." TIDENT optional-attribute-declaration-toolspace
optional-attribute-actuals ::= "(" ")"
                             | "(" attribute-actuals-list ")"
attribute-actuals-list ::=                            attribute-actual
                         | attribute-actuals-list "," attribute-actual
attribute-actual ::= actual-expression
module-declaration-start ::= optional-access-control optional-prototype "module" ident-def
module-declaration-statment ::= module-declaration-start "{" "}"
                              | module-declaration-start "{" statment-list "}"
                              | module-declaration-start "{" error "}"
optional-access-control ::= (* empty *)
                          | "public"
                          | "private"
optional-prototype ::= (* empty*)
                     | "prototype"
include-module-statment ::= "include" optional-access-control optional-prototype "module" ident-def ";"
block-statment-body ::= "{" "}"
                      | "{" statment-list "}"
                      | "{" error "}"
block-statment ::= block-statment-body
statment-list ::=               toplevel-statment
                | statment-list toplevel-statment
renames-list ::= expression
               | all-operator-name
               | expression "as" expression
               | renames-list "," expression
               | renames-list "," all-operator-name
               | renames-list "," expression "as" expression
use-renames-list ::= expression
                   | expression "as" expression
                   | expression "as" TUNDERSCORE
                   | use-renames-list "," expression
                   | use-renames-list "," expression "as" expression
                   | use-renames-list "," expression "as" TUNDERSCORE
optional-only-list ::= (* empty *)
                     | renames-list
use-statment ::= optional-access-control "use" use-renames-list ";"
               | optional-access-control "use" expression "except" renames-list ";"
               | optional-access-control "use" expression "as" expression "except" renames-list ";"
               | optional-access-control "use" expression "as" TUNDERSCORE "except" renames-list ";"
               | optional-access-control "use" expression "only" optional-only-list ";"
               | optional-access-control "use" expression "as" expression "only" optional-only-list ";"
               | optional-access-control "use" expression "as" TUNDERSCORE "only" optional-only-list ";"
import-statment ::= optional-access-control "import" import-list ";"
import-expression ::= expression
                    | expression "." all-operator-name
                    | expression "as" ident-use
                    | expression "." "{" renames-list "}"
import-list ::=                 import-expression
              | import-list "," import-expression
require-statment ::= "require" expression-list ";"
assignment-statment ::= lhs-expression assignop-ident optional-try-expression ";"
                      | lhs-expression "<=>"           optional-try-expression ";"
                      | lhs-expression "reduce="       optional-try-expression ";"
                      | lhs-expression "&&="           optional-try-expression ";"
                      | lhs-expression "||="           optional-try-expression ";"
                      | lhs-expression "="             "noinit"  ";"
optional-label-ident ::= (* empty*)
                       | TIDENT
reserved-word-ident ::= "none"
                      | "this"
                      | "false"
                      | "true"
                      | internal-type-ident-def
ident-def ::= TIDENT
            | reserved-word-ident
ident-use ::= TIDENT
            | "this"
internal-type-ident-def ::= "bool" |          "int" | "uint" | "real" | "imag" | "complex" | "bytes" | "string" | "sync" | "single" |
 "owned" | "shared" | "borrowed" | "unmanaged" | "domain" | "index" | "locale" | "nothing" | "void"
scalar-type ::=             "bool" | "enum" | "int" | "uint" | "real" | "imag" | "complex" | "bytes" | "string" |
                                                                       "locale"| "nothing" | "void"
reserved-type-ident-use ::=                                                                                       "sync" | "single" |
 "domain"                                                 | "index"
do-statment ::= "do" statment
              | block-statment
return-statment ::= "return" ";"
                  | "return" optional-try-expression ";"
class-level-statment ::= ";"
                       | inner-class-level-statment
                       | "public"
                       | "private"
inner-class-level-statment ::= fn-declaration-statment-complete
                             | var-declaration-statment
                             | enum-declaration-statment
                             | type-alias-declaration-statment
                             | class-decl-statment
                             | forwarding-declaration-statment
                             | extern-export-declaration-statment
forwarding-declaration-statment ::= forwarding-declaration-start expression ";"
                                  | forwarding-declaration-start expression "except" renames-list ";"
                                  | forwarding-declaration-start expression "only" optional-only-list ";"
                                  | forwarding-declaration-start var-declaration-statment
forwarding-declaration-start ::= "forwarding"
extern-or-export ::= "extern"
                   | "export"
extern-export-declaration-statment-start ::= extern-or-export
extern-export-declaration-statment ::= extern-export-declaration-statment-start               class-start optional-inherit "{" class-level-statment-list "}"
                                     | extern-export-declaration-statment-start STRINGLITERAL class-start optional-inherit "{" class-level-statment-list "}"
                                     | extern-export-declaration-statment-start optional-expression fn-declaration-statment
                                     | extern-export-declaration-statment-start optional-expression var-declaration-type var-declaration-statment-inner-list ";"
                                     | extern-export-declaration-statment-start optional-expression "type" type-alias-declaration-statment-inner-list ";"
extern-block-statment ::= "extern" EXTERNCODE
loop-statment ::= "do" statment "while" expression ";"
                | "while" expression do-statment
                | "while" ifvar do-statment
                | "coforall" expression "in" expression optional-task-intent-list do-statment
                | "coforall" expression "in" zippered-iterator optional-task-intent-list do-statment
                | "coforall" expression optional-task-intent-list do-statment
                | "for" expression "in" expression do-statment
                | "for" expression "in" zippered-iterator do-statment
                | "for" expression do-statment
                | "for" zippered-iterator do-statment
                | "for" "param"  ident-def "in" expression do-statment
                | "forall" expression "in" expression                                   do-statment
                | "forall" expression "in" expression              forall-intent-clause do-statment
                | "forall" expression "in" zippered-iterator                      do-statment
                | "forall" expression "in" zippered-iterator forall-intent-clause do-statment
                | "forall"          expression                                   do-statment
                | "forall"          expression              forall-intent-clause do-statment
                | "forall"          zippered-iterator                      do-statment
                | "forall"          zippered-iterator forall-intent-clause do-statment
                | "foreach" expression "in" expression                                   do-statment
                | "foreach" expression "in" expression              forall-intent-clause do-statment
                | "foreach" expression "in" zippered-iterator                      do-statment
                | "foreach" expression "in" zippered-iterator forall-intent-clause do-statment
                | "foreach"          expression                                   do-statment
                | "foreach"          expression              forall-intent-clause do-statment
                | "foreach"          zippered-iterator                      do-statment
                | "foreach"          zippered-iterator forall-intent-clause do-statment
                | "[" expression-list "in" expression "]" statment
                | "[" expression-list "in" expression forall-intent-clause "]" statment
                | "[" expression-list "in" zippered-iterator "]" statment
                | "[" expression-list "in" zippered-iterator forall-intent-clause "]" statment
                | "[" expression-list "]" statment
                | "[" expression-list forall-intent-clause "]" statment
                | "[" zippered-iterator "]" statment
                | "[" zippered-iterator forall-intent-clause "]" statment
zippered-iterator ::= "zip" "(" expression-list ")"
if-statment ::= "if" expression "then"  statment
              | "if" expression block-statment
              | "if" expression "then"  statment "else" statment
              | "if" expression block-statment "else" statment
              | "if" ifvar "then"  statment
              | "if" ifvar block-statment
              | "if" ifvar "then"  statment "else" statment
              | "if" ifvar block-statment "else" statment
              | "if" expression assignop-ident expression "then"  statment
              | "if" expression assignop-ident expression block-statment
              | "if" expression assignop-ident expression "then"  statment "else" statment
              | "if" expression assignop-ident expression block-statment "else" statment
ifvar ::= "var"   ident-def "=" expression
        | "const" ident-def "=" expression
interface-statment ::= "interface" ident-def "(" ifc-formal-list ")" block-statment
                     | "interface" ident-def                       block-statment
ifc-formal-list ::=                     ifc-formal
                  | ifc-formal-list "," ifc-formal
ifc-formal ::= ident-def
implements-type-ident ::= TIDENT
                        | "bool"
                        | "int"
                        | "uint"
                        | "real"
                        | "imag"
                        | "complex"
                        | "bytes"
                        | "string"
                        | "locale"
                        | "nothing"
                        | "void"
                        | "none"
                        | "this"
                        | "false"
                        | "true"
                        | "domain"
                        | "index"
implements-statment ::= "implements" ident-def "(" actual-list ")" ";"
                      | implements-type-ident "implements" ident-def ";"
                      | implements-type-ident "implements" ident-def "(" actual-list ")" ";"
ifc-constraint ::= "implements" ident-def "(" actual-list ")"
                 | implements-type-ident "implements" ident-def
                 | implements-type-ident "implements" ident-def "(" actual-list ")"
try-statment ::= "try"  tryable-statment
               | "try!" tryable-statment
               | "try"  block-statment catch-expression-list
               | "try!" block-statment catch-expression-list
catch-expression-list ::= (* empty *)
                        | catch-expression-list catch-expression
catch-expression ::= "catch"                                block-statment
                   | "catch"     catch-expression-inner     block-statment
                   | "catch" "(" catch-expression-inner ")" block-statment
catch-expression-inner ::= ident-def
                         | ident-def ":"expression
throw-statment ::= "throw" expression ";"
select-statment ::= "select" expression "{" when-statment-list "}"
                  | "select" expression "{" error "}"
when-statment-list ::= (* empty*)
                     | when-statment-list when-statment
when-statment ::= "when" expression-list do-statment
                | "otherwise" statment
                | "otherwise" "do" statment
manager-expression ::= expression "as" var-declaration-type ident-def
                     | expression "as" ident-def
                     | expression
manager-expression-list ::=                             manager-expression
                          | manager-expression-list "," manager-expression
manage-statment ::= "manage" manager-expression-list do-statment
class-decl-statment ::= class-start optional-inherit "{" class-level-statment-list "}"
                      | class-start optional-inherit "{" error "}"
class-start ::= class-tag ident-def
class-tag ::= "class"
            | "record"
            | "union"
optional-inherit ::= (* empty *)
                   | ":"expression-list
class-level-statment-list ::= (* empty *)
                            | class-level-statment-list                                         class-level-statment
                            | class-level-statment-list             attribute-declaration-statment-list class-level-statment
                            | class-level-statment-list pragma-list                              class-level-statment
                            | class-level-statment-list pragma-list attribute-declaration-statment-list class-level-statment
enum-declaration-statment ::= enum-header-lcbr enum-list "}"
                            | enum-header-lcbr error "}"
enum-header-lcbr ::= "enum" ident-def "{"
enum-list ::= enum-item
            | enum-list ","
            | enum-list "," enum-item
            | attribute-declaration-statment-list enum-item
            | enum-list "," attribute-declaration-statment-list enum-item
enum-item ::= ident-def
            | ident-def "=" expression
lambda-declaration-start ::= "lambda"
lambda-declaration-expression ::= lambda-declaration-start req-formal-list optional-ret-tag optional-type optional-throws-error optional-lifetime-where function-body-statment
linkage-spec-empty ::= (* empty *)
linkage-spec ::= linkage-spec-empty
               | "inline"
               | "override"
optional-fn-type-formal-list ::= (* empty *)
                               | fn-type-formal-list
fn-type-formal-list ::=                         fn-type-formal
                      | fn-type-formal-list "," fn-type-formal
fn-type-formal ::= named-formal
                 | required-intent-tag ":"formal-type
                 | formal-type
optional-fn-type-ret-type ::= (* empty *)
                            | ":"formal-or-ret-type-expression
fn-type ::= "proc(" optional-fn-type-formal-list ")" optional-ret-tag optional-fn-type-ret-type optional-throws-error
fn-expression ::= fn-type block-statment-body
                | fn-type "alias" expression
fn-declaration-statment-complete ::= fn-declaration-statment
fn-declaration-statment ::= fn-declaration-statment-inner optional-ret-tag optional-ret-type optional-throws-error optional-lifetime-where optional-function-body-statment
fn-declaration-statment-inner ::= fn-declaration-statment-start optional-this-intent-tag fn-ident optional-formal-list
                                | fn-declaration-statment-start optional-this-intent-tag assignop-ident optional-formal-list
                                | fn-declaration-statment-start optional-this-intent-tag fn-declaration-receiver-expression "." fn-ident optional-formal-list
                                | fn-declaration-statment-start optional-this-intent-tag fn-declaration-receiver-expression "." assignop-ident optional-formal-list
                                | fn-declaration-statment-start optional-this-intent-tag error optional-formal-list
fn-declaration-statment-start ::= linkage-spec proc-iter-or-operator
fn-declaration-receiver-expression ::= ident-expression
                                     | "(" expression ")"
fn-ident ::= ident-def
           | op-ident
           | ident-def "!"
op-ident ::= "&"
           | "|"
           | "^"
           | "~"
           | "=="
           | "!="
           | "<="
           | ">="
           | "<"
           | ">"
           | "+"
           | "-"
           | "*"
           | "/"
           | "<<"
           | ">>"
           | "%"
           | "**"
           | "!"
           | "by"
           | "#"
           | "align"
           | "<=>"
           | "init="
           | ":"
assignop-ident ::= "="
           | "+="
           | "-="
           | "*="
           | "/="
           | "%="
           | "**="
           | "&="
           | "|="
           | "^="
           | ">>="
           | "<<="
all-operator-name ::= op-ident
                    | assignop-ident
formal-var-arg-expression ::= "..."
                            | "..." expression
optional-formal-list ::= (* empty *)
                       | "(" formal-list ")"
req-formal-list ::= "("                   ")"
                  | "(" formal-list-inner ")"
formal-list-inner ::= formal
                    | formal-list-inner "," formal
formal-list ::= (* empty  *)
               | formal-list-inner
formal ::= named-formal
formal-ident-def ::= ident-def
                   | TUNDERSCORE
named-formal ::= optional-formal-intent-tag formal-ident-def optional-colon-formal-type optional-init-expression
               | pragma-list optional-formal-intent-tag formal-ident-def optional-colon-formal-type optional-init-expression
               | optional-formal-intent-tag formal-ident-def optional-colon-formal-type formal-var-arg-expression
               | pragma-list optional-formal-intent-tag formal-ident-def optional-colon-formal-type formal-var-arg-expression
               | optional-formal-intent-tag "(" tuple-var-declaration-statment-inner-list ")" optional-colon-formal-type optional-init-expression
               | optional-formal-intent-tag "(" tuple-var-declaration-statment-inner-list ")" optional-colon-formal-type formal-var-arg-expression
optional-formal-intent-tag ::= (* empty *)
                             | required-intent-tag
required-intent-tag ::= "in"
                      | "inout"
                      | "out"
                      | "const" "in"
                      | "const" "ref"
                      | "const"
                      | "param"
                      | "ref"
                      | "type"
optional-this-intent-tag ::= (* empty *)
                           | "param"
                           | "ref"
                           | "const" "ref"
                           | "const"
                           | "type"
proc-iter-or-operator ::= "proc"
                        | "iter"
                        | "operator"
optional-ret-tag ::= (* empty *)
                   | "const"
                   | "const" "ref"
                   | "ref"
                   | "param"
                   | "type"
optional-throws-error ::= (* empty *)
                        | "throws"
optional-function-body-statment ::= ";"
                                  | function-body-statment
function-body-statment ::= block-statment-body
                         | "do" toplevel-statment
                         | return-statment
query-expression ::= TQUERIEDIDENT
optional-lifetime-where ::= (* empty *)
                          | "where" expression
                          | "lifetime" lifetime-components-expression
                          | "where" expression "lifetime" lifetime-components-expression
                          | "lifetime" lifetime-components-expression "where" expression
lifetime-components-expression ::= lifetime-expression
                                 | lifetime-components-expression "," lifetime-expression
lifetime-expression ::= lifetime-ident "="  lifetime-ident
                      | lifetime-ident "<"  lifetime-ident
                      | lifetime-ident "<=" lifetime-ident
                      | lifetime-ident "==" lifetime-ident
                      | lifetime-ident ">"  lifetime-ident
                      | lifetime-ident ">=" lifetime-ident
                      | "return" lifetime-ident
lifetime-ident ::= TIDENT
                 | "this"
type-alias-declaration-statment ::= type-alias-declaration-statment-start type-alias-declaration-statment-inner-list ";"
type-alias-declaration-statment-start ::=          "type"
                                        | "config" "type"
type-alias-declaration-statment-inner-list ::=                                                type-alias-declaration-statment-inner
                                             | type-alias-declaration-statment-inner-list "," type-alias-declaration-statment-inner
type-alias-declaration-statment-inner ::= ident-def optional-init-type
optional-init-type ::= (* empty *)
                     | "=" expression
var-declaration-type ::= "param"
                       | "const" "ref"
                       | "ref"
                       | "const"
                       | "var"
var-declaration-statment ::= "config" var-declaration-type var-declaration-statment-inner-list ";"
                           | var-declaration-type var-declaration-statment-inner-list ";"
var-declaration-statment-inner-list ::=                                         var-declaration-statment-inner
                                      | var-declaration-statment-inner-list "," var-declaration-statment-inner
var-declaration-statment-inner ::= ident-def optional-type optional-init-expression
                                 | "(" tuple-var-declaration-statment-inner-list ")" optional-type optional-init-expression
tuple-var-declaration-component ::= TUNDERSCORE
                                  | ident-def
                                  | "(" tuple-var-declaration-statment-inner-list ")"
tuple-var-declaration-statment-inner-list ::=                                               tuple-var-declaration-component
                                            | tuple-var-declaration-statment-inner-list ","
                                            | tuple-var-declaration-statment-inner-list "," tuple-var-declaration-component
optional-init-expression ::= (* empty *)
                           | "=" "noinit"
                           | "=" optional-try-expression
formal-or-ret-type-expression ::= expression
ret-type ::= formal-or-ret-type-expression
           | reserved-type-ident-use
           | error
colon-ret-type ::= ":" ret-type
                 | error
optional-ret-type ::= (* empty *)
                    | colon-ret-type
optional-type ::= (* empty *)
                | ":"expression
                | ":"reserved-type-ident-use
                | error
formal-type ::= formal-or-ret-type-expression
              | reserved-type-ident-use
colon-formal-type ::= ":" formal-type
optional-colon-formal-type ::= (* empty *)
                             | colon-formal-type
expression-list ::=                     expression
                  | expression-list "," expression
tuple-component ::= TUNDERSCORE
                  | optional-try-expression
tuple-expression-list ::= tuple-component "," tuple-component
                        | tuple-expression-list "," tuple-component
optional-actual-list ::= (* empty *)
                       | actual-list
actual-list ::=                 actual-expression
              | actual-list "," actual-expression
actual-expression ::= ident-use "=" optional-try-expression
                    |               optional-try-expression
ident-expression ::= ident-use
                   | scalar-type
sub-type-level-expression ::= nil-expression
                            | lhs-expression
                            | cond-expression
                            | unary-operator-expression
                            | binary-operator-expression
                            | "single"  expression
                            | "index"  "(" optional-actual-list ")"
                            | "domain"  "(" optional-actual-list ")"
                            | "subdomain" "(" optional-actual-list ")"
                            | "sparse" "subdomain" "(" actual-expression ")"
                            | "atomic" expression
                            | "sync" expression
                            | "owned"
                            | "owned" expression
                            | "unmanaged"
                            | "unmanaged" expression
                            | "shared"
                            | "shared" expression
                            | "borrowed"
                            | "borrowed" expression
                            | "class"
                            | "record"
for-expression ::= "for" expression "in" expression "do" expression
                 | "for" expression "in" zippered-iterator "do" expression
                 | "for" expression "do" expression
                 | "for" expression "in" expression "do" "if" expression "then"  expression
                 | "for" expression "in" zippered-iterator "do" "if" expression "then"  expression
                 | "for" expression "do" "if" expression "then"  expression
                 | "forall" expression "in" expression "do" expression
                 | "forall" expression "in" zippered-iterator "do" expression
                 | "forall" expression "do" expression
                 | "forall" expression "in" expression "do" "if" expression "then"  expression
                 | "forall" expression "in" zippered-iterator "do" "if" expression "then"  expression
                 | "forall" expression "do" "if" expression "then"  expression
bracket-loop-expression ::= "[" "]"
                          | "[" "]" expression
                          | "[" expression-list "]" expression
                          | "[" expression-list "in" expression "]" expression
                          | "[" expression-list "in" zippered-iterator "]" expression
                          | "[" expression-list "in" expression "]" "if" expression "then"  expression
                          | "[" expression-list "in" zippered-iterator "]" "if" expression "then"  expression
cond-expression ::= "if" expression "then"  expression "else" expression
nil-expression ::= "nil"
statment-level-expression ::= nil-expression
                            | ident-expression
                            | dot-expression
                            | call-expression
                            | lambda-declaration-expression
                            | new-expression
                            | let-expression
optional-task-intent-list ::= (* empty*)
                            | task-intent-clause
task-intent-clause ::= "with" "(" task-intent-list ")"
task-intent-list ::=                      intent-expression
                   | task-intent-list "," intent-expression
forall-intent-clause ::= "with" "(" forall-intent-list ")"
forall-intent-list ::=                        intent-expression
                     | forall-intent-list "," intent-expression
intent-expression ::= task-var-prefix ident-expression optional-type optional-init-expression
                    | reduce-scan-operator-expression "reduce" ident-expression
                    | expression                      "reduce" ident-expression
task-var-prefix ::= "const"
                  | "in"
                  | "const" "in"
                  | "ref"
                  | "const" "ref"
                  | "var"
new-maybe-decorated ::= "new"
                      | "new" "owned"
                      | "new" "shared"
                      | "new" "unmanaged"
                      | "new" "borrowed"
new-expression ::= new-maybe-decorated expression
                 | "new" "owned"  "(" expression ")" "(" optional-actual-list ")"
                 | "new" "shared" "(" expression ")" "(" optional-actual-list ")"
                 | "new" "owned"  "(" expression ")" "(" optional-actual-list ")" "?"
                 | "new" "shared" "(" expression ")" "(" optional-actual-list ")" "?"
let-expression ::= "let" var-declaration-statment-inner-list "in" expression
range-literal-expression ::= expression ".." expression
                           | expression "..<" expression
                           | expression ".."
                           | ".." expression
                           | "..<" expression
                           | ".."
                           | expression "<.." expression
                           | expression "<..<" expression
                           | expression "<.."
cast-expression ::                                  |expression ":" expression
tuple-expand-expression ::= "(" "..." expression ")"
super-expression ::= fn-expression
                   | expression
expression ::= for-expression
             | sub-type-level-expression
             | sub-type-level-expression "?"
             | "?"
             | bracket-loop-expression
             | query-expression
             | literal-expression
             | fn-type
             | reduce-expression
             | scan-expression
             | lambda-declaration-expression
             | new-expression
             | let-expression
             | ifc-constraint
             | tuple-expand-expression
             | cast-expression
             | range-literal-expression
optional-expression ::= (* empty *)
                      | expression
optional-try-expression ::= "try" expression
                          | "try!" expression
                          | super-expression
lhs-expression ::= ident-expression
                 | call-expression
                 | dot-expression
                 | parenthesized-expression
call-base-expression ::= lhs-expression
                       | expression "!"
                       | sub-type-level-expression "?"
                       | lambda-declaration-expression
                       | str-bytes-literal
call-expression ::= call-base-expression "(" optional-actual-list ")"
                  | call-base-expression "[" optional-actual-list "]"
                  | TPRIMITIVE "(" optional-actual-list ")"
dot-expression ::= expression "." ident-use
                 | expression "." "type"
                 | expression "." "domain"
                 | expression "." "locale"
                 | expression "." "bytes"  "(" ")"
                 | expression "." "bytes"  "[" "]"
parenthesized-expression ::= "(" tuple-component ")"
                           | "(" tuple-component "," ")"
                           | "(" tuple-expression-list ")"
                           | "(" tuple-expression-list "," ")"
bool-literal ::= "false" | "true"
str-bytes-literal ::= STRINGLITERAL
                    | BYTESLITERAL
literal-expression ::= bool-literal
                     | str-bytes-literal
                     | INTLITERAL
                     | REALLITERAL
                     | IMAGLITERAL
                     | CSTRINGLITERAL
                     | "none"
                     | "{" expression-list "}"
                     | "{" expression-list "," "}"
                     | "[" expression-list "]"
                     | "[" expression-list "," "]"
                     | "[" assoc-expression-list "]"
                     | "[" assoc-expression-list "," "]"
assoc-expression-list ::=                           expression "alias" expression
                        | assoc-expression-list "," expression "alias" expression
binary-operator-expression ::= expression "+"  expression
                             | expression "-"  expression
                             | expression "*"   expression
                             | expression "/"   expression
                             | expression "<<"   expression
                             | expression ">>"   expression
                             | expression "%"   expression
                             | expression "==" expression
                             | expression "!=" expression
                             | expression "<=" expression
                             | expression ">=" expression
                             | expression "<" expression
                             | expression ">" expression
                             | expression "&"  expression
                             | expression "|"  expression
                             | expression "^"  expression
                             | expression "&&" expression
                             | expression "||"  expression
                             | expression "**"   expression
                             | expression "by" expression
                             | expression "align" expression
                             | expression "#" expression
                             | expression "dmapped" expression
unary-operator-expression ::= "+" expression
                            | "-"  expression
                            | "--" expression
                            | "++" expression
                            | "!"   expression
                            | expression "!"
                            | "~"  expression
reduce-expression ::= expression "reduce" expression
                    | expression "reduce" zippered-iterator
                    | reduce-scan-operator-expression "reduce" expression
                    | reduce-scan-operator-expression "reduce" zippered-iterator
scan-expression ::= expression "scan" expression
                  | expression "scan" zippered-iterator
                  | reduce-scan-operator-expression "scan" expression
                  | reduce-scan-operator-expression "scan" zippered-iterator
reduce-scan-operator-expression ::= "+"
                                  | "*"
                                  | "&&"
                                  | "||"
                                  | "&"
                                  | "|"
                                  | "^"