言語仕様 · Playground

Kairos 3 級教本 — 読解 / Reading Kairos (Grade 3 Textbook)

: v1(2026-08-02・言語 RC5 準拠・spec_head: 44493ad)。3 級のねらい=Kairos 式を受け取って、何が発火するかを 正確に読めるようになる。正本は常に言語仕様——本書は読解の 道筋を示すだけで、仕様を再定義しない。各章末の演習は本リポジトリのサンプル問題。

本書の読み方: 3 級の理解は本文と章末演習で完結する。各章末の「参照」は正本を確かめたく なったときの入口であり、読み進めるのに必須ではない——仕様書は頭から読む本ではなく辞書として 引く(実例から入るなら reference(記述語リファレンス)、 規範の字面を確かめたいときに spec)。本文の「動かして読む」の例はすべて実行検証済み: # eval: の行が評価範囲、直後のブロックがリファレンス実装の実際の出力で、教材の検証ランナーが 仕様とのずれを機械的に検査している。各例の下の「▶ Playground で開く」から、ブラウザでそのまま実行・改変できる(インストール不要・kairos-lang.org/playground)。

第 1 章 二層構造——どこに何が書いてあるか

Kairos のソースは二層でできている。premise 層(前提の供給)と本体層(スケジュールを 編む式)だ。

動かして読む——この二層がそのまま実行できる(# eval: が評価範囲・下が実際の出力):

# eval: 2026-01-01..2026-04-01
premise JP {                 # ← ここから premise 層:
  calendar-system: Gregorian #    暦法・タイムゾーン・週の始まりなど
  tz: "Asia/Tokyo"           #    「式の解釈が成り立つ条件」を並べる
  wkst: Mon
}

@JP                          # ← 前提の束を指名して……
everyDay |> within(month) |> first   # ← ここが本体層: 供給された語彙で編む一行
2026-01-01
2026-02-01
2026-03-01

▶ Playground で開く

読解の第一歩は「この式はどの前提の下で読まれているか」の確認。同じ式でも前提が変われば 意味が変わる(第 4 章で実例を見る)。契約書の前文と本文の関係と同型——前文を読まずに本文を 読んではいけない。

第 2 章 字句とリテラル——書ける形は決まっている

読解のコツ: 見慣れない並びを見たら「これは日付か・数値式か」を §5.5 の字句規則で確かめる。 たとえば 2026-01 は日付ではなく数値の引き算(2026−1)に読まれる。

動かして読む——実在しない日付は黙って直されず、その場で止まる:

# eval: 2026-01-01..2026-03-01
premise JP {
  calendar-system: Gregorian
  tz: "Asia/Tokyo"
  wkst: Mon
}

@JP
[2026-02-30]
字句エラー(8:2): 実在しない日付: 2026-02-30(月は 01..12・日は月と閏年規則の実在日のみ——proleptic Gregorian 固定。F66/ADR-43)

▶ Playground で開く

第 3 章 生成子・窓・選択子——式の背骨

本体式の基本形は「生成 → 窓で切る → 選ぶ」のパイプライン:

everyDay |> within(month) |> first

これで「毎月 1 日」になる。last なら月末、nth(25) なら各月 25 日。評価範囲は右開区間..2026-04-01 は 4 月を含まない)にも注意。

動かして読む——firstlast に変えるだけで月末列になる(2 月が 28 日である点も 言語が知っている):

# eval: 2026-01-01..2026-04-01
premise JP {
  calendar-system: Gregorian
  tz: "Asia/Tokyo"
  wkst: Mon
}

@JP
everyDay |> within(month) |> last
2026-01-31
2026-02-28
2026-03-31

▶ Playground で開く

第 4 章 前提が意味を変える——premise の読み方

第 1 章の主張の実演。次の式は「毎週の先頭日」だが、何曜日が発火するかは式に書かれていない:

everyDay |> within(week) |> first

答えは前提の wkst:(週の始まり)が握っている——wkst: Mon なら月曜列、wkst: Sun なら 日曜列。式だけ読んで答えた気になるのが 3 級で最も落ちやすい罠で、premise 層を読んでから 本体を読むという順序が読解の型になる。tz・calendar-system も同じ構図(どの暦法の「月」か、 どの壁時計の「一日」か)。

動かして読む——同じ一行を二つの前提で評価する。出る曜日が変わる:

# eval: 2026-01-05..2026-01-19
premise JPmon { calendar-system: Gregorian; tz: "Asia/Tokyo"; wkst: Mon }
premise JPsun { calendar-system: Gregorian; tz: "Asia/Tokyo"; wkst: Sun }

@JPmon
everyDay |> within(week) |> first   # 式 1: 月曜始まりの週の先頭

@JPsun
everyDay |> within(week) |> first   # 式 2: 同じ式・日曜始まり
# 式 1(2 件)
2026-01-05
2026-01-12
# 式 2(2 件)
2026-01-11
2026-01-18

▶ Playground で開く

第 5 章 結合子と filter——組み合わせを読む

複数の列は結合子で合成される: A | B(和)・A & B(積)・A \ B(差)。営業日の定番形 everyDay \ (satSun | holidays) は「全日から、土日と祝日の和を引く」と内側から読む。

filter は条件で間引く: everyDay |> filter(d => weekday(d) == Fri) は金曜だけの列。 weekday(d) は「点 d の属する窓のラベルを読む」形(束縛名射影)で、3 級では「d の曜日」と 読めれば足りる。

パイプの順序が意味を決めることも覚えておく——filter |> within |> nth(2)(金曜に濾して から各月 2 本目=第 2 金曜)と within |> nth(2) |> filter(各月 2 日のうち金曜の日だけ)は 別物。この罠の実例は 2 級で扱う。

動かして読む——営業日の定番形。2026-08-11(火)は山の日:

# eval: 2026-08-10..2026-08-17
premise JP {
  calendar-system: Gregorian
  tz: "Asia/Tokyo"
  wkst: Mon
}

@JP
holidays = [2026-08-11] covering: 2026-08-01..2026-09-01
satSun = everyDay |> filter(d => weekday(d) == Sat or weekday(d) == Sun)
everyDay \ (satSun | holidays)
2026-08-10
2026-08-12
2026-08-13
2026-08-14
# 被覆サマリ
#   holidays covering 2026-08-01..2026-09-01 残走路 16 日

▶ Playground で開く

出力の末尾に付く「被覆サマリ」は、祝日データの有効範囲と残り日数の常時表示——データが尽きる 前に教えてくれる運用の数字で、3 級では「そういう行が出る」と分かっていれば足りる(詳しくは 1 級の領分)。

巻末——3 級の到達確認

  1. premise 層と本体層の役割を人に説明できる(第 1 章)
  2. 日付・幅リテラルの合法/字句エラーを判別できる(第 2 章)
  3. 「生成→窓→選択」のパイプを声に出して読める(第 3 章)
  4. 式を読む前に前提を読む習慣がある(第 4 章)
  5. 結合子と filter の合成を内側から分解できる(第 5 章)

サンプル問題 6 問(各章末)を自力で解けたら、3 級の水準はほぼ届いている。実行環境で確かめたい ときは各問題末尾の「検証」節をリファレンス実装で 実行すればよい。