Skip to content

標準ライブラリ

Kumiki の標準ライブラリは「最小完備」を目標に設計されている。同じ目的の関数を複数提供しない(AI の選択を曖昧にしないため)。

2.1 ビルトイン型

2.1.1 プリミティブ

表現リテラル例
TextUTF-8 文字列"hello"
Int64bit 整数42, -7
Float64bit 浮動小数3.14, -0.5
Bool真偽値true, false
Unit単一値()
Bytesバイト列リテラルなし、Bytes.from-text() で生成
TimeUNIX ナノ秒リテラルなし、now または Time.parse()

2.1.2 汎化型

用途
Map(K, V)キーは Eq、値は任意
Set(T)T は Eq
List(T)順序あり、インデックスアクセス可
Option(T)None または Some(T)
Result(T, E)Ok(T) または Err(E)
Tuple(T1, ..., Tn)固定長

2.1.3 ドメイン型(標準提供)

定義
HttpStatusnominal Int where between(100, 599)
HttpError{status: HttpStatus, message: Text, body: Option(Text)}
Urlnominal Text where url
Emailnominal Text where email
Uuidnominal Text where uuid
Durationnominal Int (ナノ秒)
Route{path: Text, params: Map(Text, Text), query: Map(Text, Text)}
FormDataMap(Text, FormValue)
FormValueTextV(Text) | NumberV(Float) | BoolV(Bool) | FileV(File)
File{name: Text, size: Int, type: Text, content: Bytes}

2.2 コレクションメソッド

2.2.1 Map(K, V)

keys                        : List(K)
values                      : List(V)
entries                     : List(Tuple(K, V))  ; 実装上 [[k, v], ...] の配列
size                        : Int
is-empty                    : Bool
has(k)                      : Bool
get(k)                      : Option(V)
get-or(k, default)          : V
insert(k, v)                : Map(K, V)        ; 純粋。新 Map を返す
remove(k)                   : Map(K, V)
update(k, expr)             : Map(K, V)        ; expr の中で $1 が現在値
merge(other)                : Map(K, V)
filter(pred)                : Map(K, V)        ; pred の中で $1=key, $2=value
map(expr)                   : Map(K, V')       ; expr の中で $1=key, $2=value

.entriesList(Tuple(K, V)) として 2 要素配列の列を返す。後続の map / sort-by / filter lambda はランタイム destructure により $1=key, $2=value で扱える:

kumiki
fn sortedByCreatedAt(m: Map(Id, Item)) -> List(Id)
   = m.entries.sort-by($2.createdAt).map($1)

get-orOption 用にも使える polymorphic method:

kumiki
m.get-or(k, default)         ; Map: 値がなければ default
opt.get-or(default)          ; Option: None なら default、Some(v) なら v

.filterList と Map の両方に対して使え、ランタイムが受信側の型を見て自動振り分けする (polymorphic dispatch):

  • 受信側が List → 各要素について pred($1) を評価、true の要素だけ残す
  • 受信側が Map → 各エントリについて pred($1, $2) (key, value) を評価、true のエントリだけ残す

例えば m.keys.filter(...) のようにチェーンしたとき、m.keysList(K) を返すため filter は List のシグネチャで動く。混在チェーンを書いても型に応じた挙動になる。

2.2.2 Set(T)

size                        : Int
has(x)                      : Bool
add(x)                      : Set(T)
remove(x)                   : Set(T)
toggle(x)                   : Set(T)
union(other)                : Set(T)
intersect(other)            : Set(T)
diff(other)                 : Set(T)
to-list                     : List(T)

2.2.3 List(T)

length                      : Int
is-empty                    : Bool
get(i)                      : Option(T)
head                        : Option(T)
tail                        : List(T)
last                        : Option(T)
push(x)                     : List(T)
prepend(x)                  : List(T)
concat(other)               : List(T)
slice(start, end)           : List(T)
reverse                     : List(T)
sort                        : List(T)          ; T は Ord
sort-by(expr)               : List(T)
unique                      : List(T)
map(expr)                   : List(T')
filter(pred)                : List(T)
contains(x)                 : Bool
find(pred)                  : Option(T)
fold(init, expr)            : Acc              ; expr の中で $1=acc, $2=elem
join(sep)                   : Text             ; T が Text
chunk(n)                    : List(List(T))
zip(other)                  : List(Tuple(T, U))

括弧なしショートカット: 引数なしメソッド(is-empty / length / reverse / sort / unique / head / tail / last)は () を省略して field のように書ける

kumiki
slot todos : List(Todo) = []
fn count() -> Int = todos.length              ; 括弧なし OK
fn empty?() -> Bool = todos.is-empty          ; 同上
fn norm() -> List(Todo) = todos.reverse       ; 同上

dispatch 規則(v0.3、ADR-002). recv.m は名前ではなく recv推論型で dispatch される:recvm という名のフィールドを持つ record ならフィールドを読み、m メソッドを持つ stdlib 型ならショートカットを使う。よってメソッドと同名の record フィールド({head, …} への node.head)はフィールドとして読まれ、shadow されない。受け手型が既知m がフィールドでもメンバーでもないときはコンパイルエラー(errors.md E0108)。受け手型が推論できないとき(例:型のない reducer payload)は従来の名前ベース dispatch を使う。

map / filter / sort-by の lambda 引数:

  • List 要素には $1 を、.entries 後の [k, v] ペアには $1=key, $2=value を束縛します(ランタイムが自動 destructure)
  • 例: m.entries.sort-by($2.createdAt).map($1)$1=key, $2=value

2.2.4 Option(T)

is-some                     : Bool
is-none                     : Bool
get                         : T               ; None なら panic(reducer 内のみ許可)
get-or(default)             : T
map(expr)                   : Option(T')
flat-map(expr)              : Option(T')
filter(pred)                : Option(T)
or(other)                   : Option(T)
to-list                     : List(T)

2.2.5 Result(T, E)

is-ok                       : Bool
is-err                      : Bool
get                         : T               ; Err なら panic
get-err                     : E               ; Ok なら panic
get-or(default)             : T
map(expr)                   : Result(T', E)
map-err(expr)               : Result(T, E')
flat-map(expr)              : Result(T', E)
or(other)                   : Result(T, E)
to-option                   : Option(T)

panic 意味論(v0.3). Option.get / Result.get(多相 unwrap、カッコ無しで value.get とも書ける)は空ケース(None / Err)で panic し、Result.get-errOk で panic する。いずれも live runtime が扱う唯一の制御された panic シグナルを送出する — lifecycle.md §7.2 を参照。reducer 外では get-or(default) を推奨。

2.2.6 Text

length                      : Int
is-empty                    : Bool
upper                       : Text
lower                       : Text
trim                        : Text
starts-with(s)              : Bool
ends-with(s)                : Bool
contains(s)                 : Bool
split(sep)                  : List(Text)
replace(from, to)           : Text
slice(start, end)           : Text
parse-int                   : Option(Int)
parse-float                 : Option(Float)

2.2.7 Int / Float

abs, neg, min(b), max(b), clamp(lo, hi)
show, to-float (Int), to-int (Float, 切り捨て)

x.show全型共通の文字列化メソッド。Int / Float / Bool / variant / nominal すべて .show : Text を返す。Kumiki には to-text という名前は存在しない。

2.2.8 Time

Time.now                    : Time
Time.parse(text)            : Option(Time)    ; ISO8601
plus(duration)              : Time
minus(duration)             : Time
diff(other)                 : Duration
format(pattern)             : Text            ; "yyyy-MM-dd HH:mm"

2.2.9 Duration

Duration.ms(n)              : Duration
Duration.s(n)               : Duration
Duration.m(n)               : Duration   ; min と書いても可
Duration.h(n)               : Duration
Duration.d(n)               : Duration   ; days と書いても可
to-ms                       : Int

Time / Duration はランタイム上では raw ミリ秒数として表現される。time.plus(Duration.h(72)) のような演算は単なる ms 加算に展開される。

kumiki
fn isSoon(due: Time) -> Bool = due < now.plus(Duration.h(72))
fn elapsed(start: Time) -> Duration = now.diff(start)

2.3 tile プリミティブ要素

Kumiki の組み込みタイル。意味タグであり HTML タグの直訳ではない。

2.3.1 構造要素

要素役割主な props
pageアプリのルート画面title, class
region名前付きセクションaria-label, class
row水平レイアウトgap, align, justify
column垂直レイアウトgap, align, justify
stack重ね配置align
gridグリッドcols, gap
box汎用コンテナclass, style
cardカードclass
panelパネルclass
divider区切りorientation
scrollスクロールコンテナdirection, max-height

2.3.2 テキスト要素

要素役割主な props
textテキスト表示strike, bold, italic, size, color
heading見出しlevel (1-6)
linkリンクto, external
codeコードlang
markdownMarkdown 描画(内容は引数)

2.3.3 メディア要素

要素役割主な props
image画像src, alt, width, height, loading
iconアイコンname, size
video動画src, controls, autoplay

2.3.4 入力要素

要素役割主な props
buttonボタンtext, onClick, variant, disabled, loading
inputテキスト入力bind, placeholder, type (text/email/password/...), disabled
textarea複数行入力bind, rows, placeholder
checkチェックボックスvalue, onClick, label
radioラジオボタンname, value, selected, onClick
selectセレクトbind, options (List of {label, value}), placeholder
sliderスライダーbind, min, max, step
switchトグルvalue, onClick

2.3.5 フォーム

要素役割主な props
formフォーム(form をラップする tile に ui.submit(WrapperTile) で届く)id, auto-complete, novalidate
labelラベルfor
fieldsetフィールド集合legend
errorバリデーションエラー表示field

2.3.6 リスト・表

要素役割主な props
listリストordered
list-itemリスト項目
table
table-head表ヘッダ
table-body表本体
table-row表行
table-cell表セルcolspan, rowspan

2.3.7 オーバーレイ

要素役割主な props
modalモーダルopen, onClose, title
drawerドロワーopen, onClose, side
tooltipツールチップtext, placement
popoverポップオーバーopen, onClose, placement
toastトースト通知kind (info/success/warn/error), text

2.3.8 フィードバック

要素役割主な props
spinnerスピナーsize
progressプログレスバーvalue, max
skeletonスケルトンkind (text/box/circle)

spinner はアニメーションするローディングインジケータをレンダーする(role="status" を持つアクセシブルな要素。アニメーションは prefers-reduced-motion 下で無効化される)。size はトークン sm / md / lg / xl のいずれかを取り、指定がなければ周囲のテキストサイズに追従する。

2.3.9 制御要素

要素役割
when(cond, tile)cond が true なら tile を表示
if cond then tA else tB条件分岐
for x in coll tile反復
route-outletネストルートの出力位置
link(to=...)ルート遷移リンク

2.3.10 props の共通仕様

すべての tile は次の共通 props を受ける(ビルトイン):

prop意味
classTextスタイルクラス名
styleMap(Text, Text)インラインスタイル(最小限の使用を推奨)
ariaMap(Text, Text)ARIA 属性
keyTextfor 内で要素を一意に識別
test-idTextテスト用 ID

2.4 ビルトイン関数

2.4.1 ID 生成

TypeName.fresh()           : T            ; nominal 型の新 ID(UUIDv7)

2.4.2 時刻

now                        : Time          ; 現在時刻

2.4.3 型変換

TypeName.parse(text)       : Option(T)    ; nominal 型の文字列パース
TypeName.show(value)       : Text         ; 値の文字列表現

2.4.4 数学

math.abs, math.min, math.max, math.clamp
math.floor, math.ceil, math.round
math.sqrt, math.pow, math.log, math.exp
math.random                : Float        ; reducer 内のみ呼び出し可(effect 扱い)

2.4.5 文字列フォーマット

fmt(template, ...args)     : Text         ; "Hello {0}, you have {1}"

+Text と他型を結合した場合、自動で show 相当が呼ばれる。

2.4.6 デバッグ補助

trace(label, value)        : T            ; episode log にラベル付きで記録、値はそのまま返す
panic(message)             : never        ; プログラムを停止(reducer 内のみ)

2.5 標準 capability

app.caps で宣言できる capability の標準セット:

capability用途
http.get, http.post, http.put, http.patch, http.deleteHTTP リクエスト
storage.read, storage.writelocalStorage
session.read, session.writesessionStorage
indexed.read, indexed.writeIndexedDB
nav.push, nav.replace, nav.backルート遷移
clipboard.read, clipboard.writeクリップボード
notification.showデスクトップ通知
analytics.send計測イベント送信
log.writeログ出力
crypto.random, crypto.hash暗号
media.camera, media.microphoneメディアデバイス
geo.read位置情報
socket.connect, socket.sendWebSocket

標準でも登録済みでもない capability を app.caps に書くとコンパイルエラー(E0302)。

カスタム capability の登録(kumiki.caps.json

プロジェクトは、.kumiki ファイルと同じディレクトリに kumiki.caps.json マニフェストを置くことで、受理される集合を拡張できる:

json
{
  "capabilities": [
    { "name": "telemetry.track", "description": "..." }
  ]
}

各エントリは group.action 形式(小文字・ドット区切り)の capability 名で、裸の文字列でも description を持つオブジェクトでもよい。登録された名前は app.caps で受理され、それに紐づく effect(effect track cap=telemetry.track …)は emit 可能になり、capability 境界で dispatch される — 標準 effect と全く同様に scenario でモックできる。標準集合に既にある名前は再宣言してはならない。

これは capability 境界の登録、すなわち宣言的マニフェストであって、新しい構文や任意コードではない — Kumiki の非ゴール「マクロ/DSL 拡張をしない」と整合する。動く例:packages/examples/features/27-custom-capability.kumiki(+ その kumiki.caps.json)。

未処理の effect エラーは surface され、決して silent にならない。 err に解決した effect は、対応するすべての .err reducer へ配送される。プログラムがその effect に .err reducer を一切配線していない場合、捨てられたエラーは console.error[kumiki] effect "<name>" returned an error with no .err reducer: …)で報告され、検証 tier(console.error を捕捉する smoke / runScenario)が検知する — live panic モデル(lifecycle.md §7.2)と整合する。失敗した capability が no-op に見えてはならない:storage 利用不可ケース(opaque-origin サンドボックス、プライベートモード)がまさにこれで、storage.read / storage.writeerr を返し、.ok だけを扱うアプリは黙って何もしないことになる。よってデフォルト契約は err + surface された報告であり、プログラムは .err reducer(空でもよい)を配線してエラーを処理(または意図的に無視)することを選ぶ。in-memory storage フォールバックはデフォルト挙動ではない(契約を覆い隠すため);欲しいホストは storage.* provider で明示的に供給する。


2.6 標準 effect

各 capability に対応する標準 effect。app.caps に capability があれば自動で使える。

→ 詳細仕様は HTTP / Storage

2.6.1 ナビゲーション

kumiki
effect navigate    cap=nav.push     in={path: Text, params: Map(Text, Text)}  out=Unit
effect navigate-replace cap=nav.replace in={path: Text, params: Map(Text, Text)} out=Unit
effect navigate-back   cap=nav.back  in=Unit  out=Unit

2.6.2 トースト

kumiki
effect toast       cap=notification.show  in={kind: Text, text: Text}  out=Unit

2.6.3 ログ

kumiki
effect log         cap=log.write    in={level: Text, message: Text, data: Map(Text, Text)}  out=Unit

2.7 数値・通貨など、よく欲しがる型は意図的に未提供

Money, Percent, Decimal などはアプリ側で nominal を使って定義する。Kumiki は意見を持たない。

kumiki
type Cents = nominal Int where positive
type Yen   = nominal Int where positive