表現力検証 1: 国民の祝日と生活系スケジュール
本書は Kairos の表現力検証(README.md の判定基準・記法規約を参照)の第 1 部。日本の国民の祝日
(祝日法)と、利用者が日常的に書く生活系スケジュールを対象にする。各例は五点セット
〈仕様+期待値/糖衣形/core 展開/判定/綻び〉で書く。綻びの集約は 90-findings.md。
前提: 断りがなければ前文は @JP(calendar-system: Gregorian・tz: "Asia/Tokyo"・wkst: Mon)。
暫定語彙(日付リテラル・cycle ラベル述語・week 窓など)は draft §1.14 に従う。
このファイルで共通に使う補助定義(月ラベル。単位窓以外への cycle=§1.14 暫定):
premise JPX = Gregorian with {
monthName = month cycle [Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec] anchor: 2000-01-01
}
1.1 固定日の祝日(元日・建国記念の日)
仕様: 毎年 1 月 1 日(元日)、毎年 2 月 11 日(建国記念の日)。 期待値: 2026-01-01(木)、2026-02-11(水)。
# 糖衣(onMonthDay は下で定義する糖衣)
@JPX
newYearsDay = onMonthDay(Jan, 1)
foundationDay = onMonthDay(Feb, 11)
# 糖衣の定義(§1.13 の = 束縛。専用構文なし)
onMonthDay(M, D) = within(month) |> nth(D) |> filter(d => monthName(d) == M)
# core 展開
@JPX
everyDay |> within(month) |> nth(11) |> filter(d => monthName(d) == Feb) # 建国記念の日
各月窓の第 D 日を採り、月ラベルで絞る。「毎年 M 月 D 日」に直接対応する core は無く、 窓序数(nth)+並列ラベル(cycle)の合成で書く。
判定: 書ける(暫定語彙に依存: cycle ラベル述語・月への cycle)。
綻び:
- (F1) 「毎年 M 月 D 日」という最頻出パターンが素の core では回りくどい。糖衣
onMonthDayで吸収できるが、 標準糖衣として言語側に置くべき水準の頻度。 - (F2)
monthNameは Gregorian に無いので派生で足した。月ラベル(と年内月番号)は標準 premise が 提供すべきではないか(monthOfは「month 通し番号→月位置」の値関数で、「点→月」の射影が無い)。 - (F3) 単位窓(day)以外への
cycle(ここでは month への 12 ラベル)を初めて実使用。anchor:の 「属する窓が先頭ラベル」解釈(§1.14)で素直に読めた。年窓への適用は02-cycles.mdで検証。
1.2 ハッピーマンデー(成人の日・海の日・敬老の日・スポーツの日)
仕様: 成人の日=1 月第 2 月曜。海の日=7 月第 3 月曜。敬老の日=9 月第 3 月曜。スポーツの日=10 月第 2 月曜。 期待値(2026 年): 成人の日 2026-01-12、海の日 2026-07-20、敬老の日 2026-09-21、スポーツの日 2026-10-12。
# 糖衣
@JPX
comingOfAgeDay = nthWeekdayOfMonth(2, Mon, Jan)
marineDay = nthWeekdayOfMonth(3, Mon, Jul)
respectAgedDay = nthWeekdayOfMonth(3, Mon, Sep)
sportsDay = nthWeekdayOfMonth(2, Mon, Oct)
nthWeekdayOfMonth(n, w, M) = filter(d => weekday(d) == w) |> within(month) |> nth(n)
|> filter(d => monthName(d) == M)
# core 展開(成人の日)
@JPX
everyDay |> filter(d => weekday(d) == Mon) |> within(month) |> nth(2) |> filter(d => monthName(d) == Jan)
月曜だけ残して月ごとに束ね、各月窓の第 2 を採る。stdlib/gregorian.md §4.4 の言う通り、「月の第 N 月曜」は
weekday ラベルだけで決まり WKST 非依存(週窓を使わないので wkst: の取り違えの影響を受けない)。
判定: 書ける(暫定語彙に依存: cycle ラベル述語)。
綻び:
- (F4) cycle ラベルの述語参照
weekday(d) == Mon(§1.14 暫定)が無いとこの最頻出パターンが書けない。 暫定の「束縛名を点→ラベルの値関数として読む」は自然に機能した。確定を推す。
1.3 春分の日・秋分の日(官報告示版)
仕様: 天文学上の春分日・秋分日。前年 2 月に暦要項(官報)で確定する。規則からは生成できない (太陽黄経 0°/180° の通過日=天文データ)。 期待値: 春分の日 2026-03-20、秋分の日 2026-09-23。
# 日付リテラルのリストをストリームとして直書き(テーブルリテラル。ADR-26)。値は暦要項の実データ
premise JPGazette {
source: "cao.go.jp/official" # 官報告示(春分秋分の日は暦要項に基づき前年 2 月閣議決定)
asof: 2025-02-03 # 令和8年暦要項の告示
vernalEquinoxDay = [2025-03-20, 2026-03-20, 2027-03-21]
autumnalEquinoxDay = [2025-09-23, 2026-09-23, 2027-09-23]
}
実データ照合(NAOJ 暦要項各年・95-reference-data.md): 春分の日 2025-03-20/2026-03-20/2027-03-21、
秋分の日 いずれも 09-23。上のテーブルリテラルは実データと完全一致(2027 春分が 3/21 も的中)。
判定: 要補完。受け皿(ストリームとしての利用・カスケードへの合流)は既存語彙で足りるが、
「日付リテラルの列をストリーム定数として書く」テーブルリテラルが未定義(値リスト […] は §1.14 暫定に
あるが、要素が時点でリストがストリームに昇格する規則が無い)。天文計算式による近似版は 03-astronomical.md。
綻び:
- (F5) テーブルリテラル(日付リスト→ストリーム)が無い。官報告示のような「規則でなくデータで確定する
小規模な列」の持ち込み口として必須。
source:/asof:と同居させると出所と版が premise に載る(ADR-15/16 と 整合)。→ 補完機構の本命 1。 - (F6) データの尽きる端(2028 年以降が未告示)で列が黙って途切れる。ADR-15 の「事故の空」出自注釈がここで 実際に必要になる(正当な空でなくデータ未投入)。テーブルリテラルは有効範囲(asof の裏返し)を持つべきか。
1.4 振替休日
仕様(祝日法 3 条 2 項): 祝日が日曜に当たるとき、その後の最も近い「祝日でない日」を休日とする。 期待値: 2026-05-06(水)。2026 年は 5/3 憲法記念日が日曜 → 5/4 みどりの日・5/5 こどもの日を飛び越え、 5/6 が振替休日。
@JPX
statutory = newYearsDay | comingOfAgeDay | foundationDay | … # 1.1〜1.3 の祝日全部の和
nonHoliday = everyDay \ statutory
substitutes = statutory |> filter(d => weekday(d) == Sun) |> roll(Following, on: nonHoliday)
holidays = statutory | substitutes # カスケード(和・後勝ち)
日曜の祝日だけ残し、roll(Following) で「祝日でない日」軸の次の有効点へ寄せる。連休(GW)を
自動で飛び越えるのは roll の軸に nonHoliday を選んだ帰結で、5/4・5/5 は無効点として素通りする。
移動でなく和で足す(元の日曜も休日のまま)は ADR-01 のカスケード分解そのもの。
判定: 書ける。既存語彙(filter・roll・結合子)が法文の構造にそのまま対応した。
綻び:
- (F7)
rollの軸に「導出したストリーム(nonHoliday)」を渡した。既存例はon: bizDay(premise 解決の軸名) のみで、任意ストリームを軸として渡せるかは未規定。閉包(I2)からは自然だが、軸(axis)とストリームの 型関係の明文化が要る。 - (F8)
statutoryの定義が振替の入力になり、holidaysがstatutoryに振替を足す——substitutesの 「祝日でない日」は振替を含まない statutory 基準でよいか(法文は「国民の祝日」でない日=振替を含まず、 現行の書き方が正しい)。ただし連続振替(理論上)の再帰は書けない。固定回数の展開で実用上足りる。
1.5 国民の休日
仕様(祝日法 3 条 3 項): 前日と翌日の両方が祝日である日(祝日でない日に限る)は休日とする。 期待値: 2026-09-22(火)。敬老の日 9/21(月)と秋分の日 9/23(水)に挟まれる。
@JPX
sandwiched = ((statutory |> shift(+1, unit: day)) & (statutory |> shift(-1, unit: day))) \ statutory
「祝日の翌日」の集合と「祝日の前日」の集合の積が「両隣が祝日の日」。祝日自身を差で除く。
結合子の積 & の初の実用例。
判定: 書ける。集合演算の見本のような一行。
綻び: なし(& の優先度は同一・左結合=括弧必須の規約がここで効いた。括弧を忘れると
statutory |> shift(+1) & statutory の解釈が割れるが、規約により静的に括弧を要求される)。
1.6 年限定の特例(2020/2021 東京五輪の祝日移動)
仕様: 2020 年に限り海の日→7/23・スポーツの日→7/24・山の日→8/10 へ移動(2021 年も同様に 7/22・7/23・8/8)。法改正(2018-11 成立、2020-12 再改正)による版の差。 期待値: 2020-07-23・2020-07-24・2020-08-10 が祝日。2020-07-20(第 3 月曜)・2020-10-12(第 2 月曜)・ 2020-08-11 は祝日でない。
premise JP2020 {
source: "cao.go.jp/official"
asof: 2020-12-04 # 改正後の版
olympicsRemoved = [2020-07-20, 2020-10-12, 2020-08-11, # 移動元(本則が生む日)
2021-07-19, 2021-10-11, 2021-08-11]
olympicsAdded = [2020-07-23, 2020-07-24, 2020-08-10,
2021-07-22, 2021-07-23, 2021-08-08]
}
@JPX
holidays2020 = (statutory \ olympicsRemoved) | olympicsAdded | substitutes
本則(statutory)から移動元を差で除き、特例日を和で足す。宣言順の後勝ち(カスケード)で
「例外は本則の後に書く」が読み順そのまま。どの版かは asof: が、誰のデータかは source: が
識別する——「ある年だけ違う」は暦法でなくカレンダーの版差、という設計(ADR-15/16/19)の実例。
判定: 書ける(テーブルリテラル F5 に依存)。
綻び:
- (F9) 移動「元」の列挙は本則の式(第 3 月曜など)がその年に生む値を手で書き写している。
「
marineDayの 2020 年分」を式で指せると重複が消える(例:marineDay & year(2020)——年窓との積。 ただしyear(2020)という「特定の年の日々」を指す式も未定義)。→ 特定窓インスタンスの参照が無い。
1.7 給料日(25 日・休日なら前営業日)
仕様: 毎月 25 日。土日祝なら直前の営業日に前倒し。 期待値: 2026-01-23(金)(1/25 は日曜)、2026-04-24(金)(4/25 は土曜)、2026-02-25(水)(平日そのまま)。
@JP
payday = everyDay |> within(month) |> nth(25) |> roll(Preceding, on: bizDay)
判定: 書ける。既存の代表例(月末 3 営業日前)と同型で、素直に一行。
綻び: なし。ただし bizDay の解決先=カレンダー実体(祝日集合をどう calendar: JP に束ねるか)の
定義構文が未規定(F10。1.4 の holidays を作った後、それをカレンダーとして登録する接続が書けない。
→ その後 ADR-35 で確定=2026-07-08・予約公開語 nonWorking を持つ premise)。
1.8 ゴミ収集日(第 1・第 3 水曜)
仕様: 毎月第 1 と第 3 の水曜日。 期待値: 2026-07-01・2026-07-15(2026 年 7 月の水曜は 1, 8, 15, 22, 29)。
@JP
gomiDay = (wednesdays |> within(month) |> nth(1)) | (wednesdays |> within(month) |> nth(3))
wednesdays = everyDay |> filter(d => weekday(d) == Wed)
判定: 書ける。「月の第 N 曜日」(1.2 と同型)の和。WKST 非依存。
綻び:
- (F11)
nth(1) | nth(3)のような「同じ窓の複数序数」は列挙するしかない(nth([1, 3])は未定義)。 頻度は高い(隔週系はほぼこれ)。リスト引数の許容は検討価値あり。
1.9 中国の調休(2024 年春節)
仕様: 2024-02-10(土)〜02-17(土)を連休とし、代わりに 02-04(日)・02-18(日)を出勤日にする (休日の反転)。 期待値: 2024-02-04・2024-02-18 は営業日。2024-02-12(月)〜02-16(金)は休日。
premise CN2024 { source: "gov.cn/official"; asof: 2023-10-25 }
springFestival = [2024-02-10, 2024-02-11, 2024-02-12, 2024-02-13,
2024-02-14, 2024-02-15, 2024-02-16, 2024-02-17]
makeupWorkdays = [2024-02-04, 2024-02-18]
cnNonWorking = (weekends | springFestival) \ makeupWorkdays # 後勝ちの差=反転
週末カスケードの後に差を書く=「日曜だが出勤」の反転。ADR-01 が「純粋な集合差では導けない」と した反転がカスケード(和・差の左結合)で一行に収まることの検証。
判定: 書ける(テーブルリテラル F5 に依存)。
綻び: (F12) 連続 8 日の列挙が鈍い。日付リテラルの範囲(2024-02-10..2024-02-17)がほしい
(テーブルリテラルの糖衣として自然)。
小括
| 例 | 判定 | 依存する暫定/欠落 |
|---|---|---|
| 固定日祝日 | 書ける | cycle ラベル述語・月への cycle・onMonthDay 糖衣(F1/F2/F3) |
| ハッピーマンデー | 書ける | cycle ラベル述語(F4) |
| 春分・秋分(官報版) | 要補完 | テーブルリテラル(F5/F6) |
| 振替休日 | 書ける | ストリームを roll の軸に(F7/F8) |
| 国民の休日 | 書ける | — |
| 五輪特例 | 書ける | テーブルリテラル・特定年の窓参照(F9) |
| 給料日 | 書ける | カレンダー実体の登録構文(F10→ADR-35 で確定) |
| ゴミ収集日 | 書ける | nth のリスト引数は無し(F11) |
| 中国調休 | 書ける | テーブルリテラル・日付範囲(F12) |
祝日体系の構造(固定日・第 N 曜日・振替・挟まれ・年限定特例・反転)は既存語彙+暫定語彙で全て 表現できた。欠けているのは構造でなくデータの持ち込み口(テーブルリテラル)と、点→ラベル/序数の 値射影まわりである。