第18章 データセグメント
この章の目的
この章の終わりまでに、loop 関数のあるサイクルから次のサイクルへと生き残る状態を保持できるようになります。
記憶の問題
loop 関数は、サイクルごとに同じ本体を実行します。何かを記憶する必要があると仮定してください。小節のどの拍にいるか、次にどの音が来るか、などです。第5章では、束縛は変更できず、本体の内側で作られた束縛は次のサイクルが始まるまでには消えていることを確立しました。ここまでの言語の状態では、loop 関数は何も記憶できません。
データセグメント
その答えがデータセグメントです。それは、プログラムのメモリのうち変更しうる唯一の領域であり、その値はあるサイクルから次のサイクルへと生き残ります。これは data という語で宣言されます。
data state {
steps: [Word; 4],
}
loop main(input: Word) -> Word {
for i in 0..4 {
state.steps[i] = state.steps[i] + 1;
}
let _ = yield state.steps[0];
0
}
data ブロックは構造体のように見え、そのフィールドは state.steps のようにドットで読み取られます。違いは、そのフィールドが = で代入でき、代入されたものが次のサイクルでもまだそこにあることです。
データセグメントは、すべてのフィールドがゼロになった状態で始まります。上記のプログラムには4つのカウンタがあります。最初のサイクルで各カウンタは1になります。2回目のサイクルでは、RESET を生き延びたことにより、各カウンタは2になります。データセグメントが記憶するため、カウンタはサイクルごとに上昇していきます。
ここでループが本当の仕事をします
上記の for ループを再び見て、第8章を思い出してください。そこでは、アトミックな fn の中の for ループは、束縛が変化しないため結果を組み立てることができませんでした。ここでは同じ for ループが本当の仕事をします。各回が state.steps に書き込み、データセグメントは実際に変化します。まさに第8章が約束したとおり、ここがループがその存在意義を果たす場所です。
3種類の data ブロック
data ブロックには、その可視性を示す印を付けることができます。
- 上記のような素の
dataブロックは shared です。ホストもそれを読み書きできます。これは、ホストとプログラムがその間で状態をやり取りする方法です。 private dataブロックは、プログラム自身のメモリです。それはサイクルをまたいで持続しますが、ホストには見えません。const dataブロックは、読み取り専用の構成であり、プログラムの寿命の間固定され、決して代入されません。
shared は一般的なケースであり、最初に始めるべきものです。
プログラムの実行
プログラムを counters.kel として保存し、実行してください。
keleusma run counters.kel --tick-interval 1s
プログラムは1秒に1回 yield し、各サイクルでデータセグメントは前のサイクルからの状態を保持します。停止するには Control-C を押してください。
プログラムはバイトコードファイルにコンパイルすることもできます。
keleusma compile counters.kel -o counters.bin
このツールは wrote counters.bin (2716 bytes) のような行を出力します。第VIII部では、ピアノロールの中でデータセグメントを使ったより手の込んだプログラム、すなわち楽曲を実行します。
この章のまとめ
- データセグメントは、変更しうる唯一のメモリ領域であり、あるサイクルから次のサイクルへと生き残ります。
data name { field: Type, ... }はそれを宣言します。name.fieldはフィールドを読み取り、name.field = value;はフィールドに書き込みます。loop関数の中のforループは、データセグメントに書き込むことで本当の仕事をします。- data ブロックは、既定では
sharedであり、あるいはprivate、あるいはconstです。
これで、言語の中核である第IV部が完了しました。3種類の関数、ホストとの yield によるやり取り、loop 関数とそのサイクル、そしてそれに記憶を与えるデータセグメントを見てきました。第V部では、プログラムが実行を許可される前に通過しなければならない検査について説明します。