Types and values
Data types#
Faber 採用靜態、型別優先的型別系統。每個宣告都將型別置於名稱之前:文字 名稱,而非 名稱: 文字。型別系統涵蓋純量原始型別、泛型集合、定寬數值、張量,以及面向 GPU 的暫存器型別。
原始型別#
| 型別 | 作用 | 字面值範例 |
|---|---|---|
文字 | Unicode 字串 | "Salve, munde" |
ascii | 固定機器權杖 | 'solum:lege' |
i32 | 有號整數 | 42 |
f64 | 浮點數 | 3.14 |
布林 | 布林值 | 真、假 |
空值 | 單位/無值 | — |
無 | 空值/不存在 | 無 |
執行個體 | 持續時間/時間瞬間 | — |
JSON | 編譯期 JSON 值 | { "key": "value" } |
位元組 | 十六進位位元組序列 | \|00ff\| |
定寬數值型別#
在型別位置寫定寬。這些就是數值型別 — 與 Math in the ether 相同的列表:
| 族 | 定寬 |
|---|---|
| 有號 | i8 i16 i32 i64 |
| 無號 | u8 u16 u32 u64 |
| 十進位 | d64 |
| 無界整數 | inf |
| 浮點 | f16 bf16 f32 f64 |
入口 {
定值 i32 narrow ← 7 ∷ i32
定值 u64 wide ← 255 ∷ u64
定值 f32 single ← 1.5 ∷ f32
}定寬標記本身就是型別。
可空型別#
可空值使用聯集語法 T ∪ 無:
函式 find(文字 key) → 整數 ∪ 無 {
傳回 可空
}
函式 maybe() → 文字 ∪ 無 {
傳回 可空
}Faber 不提供 T? 或 Option<T> 語法。聯集必須明確寫出。
型別別名#
型別 UserId = 整數泛型#
函式、型別別名、類型 和 待實作介面 使用 <T> 語法接受型別參數:
函式 identitas<T>(T 值) → T {
傳回 值
}
函式 primum<T>(列表<T> res) → T ∪ 無 {
傳回 res.第一個()
}支援在呼叫位置明確指定型別引數:
函式 identitas<T>(T 值) → T {
傳回 值
}
入口 {
定值 整數 value ← identitas<整數>(7)
}集合#
| 型別 | 作用 | 簡寫 |
|---|---|---|
列表<T> | 有序動態集合 | lf32、lu32 |
表格<K, V> | 鍵值對映 | — |
張量<T, Figura> | 密集固定形狀緩衝區 | tf32[4]、ti64[2,3] |
稀疏<T, Figura> | 稀疏固定形狀緩衝區 | sf32[4]、si64[2,3] |
區間 | 範圍型別 | — |
副本<T> | 無序集合 | — |
迭代器<T> | 惰性串流 | — |
入口 {
定值 列表<整數> nums ← [1, 2, 3]
定值 表格<文字, 整數> scores ← { "alice": 10, "bob": 20 }
}張量型別#
張量<T, Figura> 是密集固定形狀容器:
| 形式 | 意義 |
|---|---|
張量<T, Figura> | 標準拼寫 |
張量<T, []> | 秩 0(純量容器) |
張量<T, _> | 形狀推論缺口 |
張量<T, [N]> | 秩 1 向量 |
張量<T, [N, M]> | 秩 2 矩陣 |
入口 {
定值 張量<f32, []> scalar ← 空集
定值 張量<整數, [4]> row ← [1, 2, 3, 4] ↦ 張量<整數, [4]>
定值 整數 ∪ 無 first ← row[0]
}GPU 核心型別#
系統層會辨識這些型別,以支援 GPU 與暫存器工作。 不具備硬體支援的套件目標會拒絕這些型別:
函式 half(f16 x) → f16 { 傳回 x }
函式 add(矩陣<f32, [2, 2]> a, 矩陣<f32, [2, 2]> b) → 矩陣<f32, [2, 2]> {
傳回 a.addita(b)
}
函式 swap(原子<i32> cell, i32 value) → i32 {
傳回 cell.exchange(value)
}型別上的借用標記#
借用標記(從、傳入、擁有)可出現在參數位置的型別上,用來指出值的傳遞方式:
# shared borrow — caller retains ownership
functio imprime(de textus label) → vacuum { }
# mutable borrow — caller lends mutable access
functio duplica(in numerus value) → vacuum { }
# move — caller gives up ownership
functio consume(own textus buffer) → textus {
redde buffer
}比較規則#
| 運算子 | 類別 | 行為 |
|---|---|---|
≡、≠、≢ | 精確相等 | 必須使用相同型別;無 可略過此要求 |
≅、≇ | 提升後精確相等 | 數值寬度合併後精確比較 |
≈、≉ | 模糊相等 | 容差匹配——isclose 預設(rel_tol 1e-09);僅數值運算元 |
<、≤、>、≥ | 排序 | 數值、瞬間、純量文字 |
內含 | 範圍包含 | 數值位於範圍內 |
之間 | 集合成員資格 | 元素位於集合內 |
Variables and binding#
Faber 有三個變數關鍵字,以及專用的指派字元。關鍵差異在於 定值(只能寫入一次)與 變值(可自由重新指派),以及 ←(執行期流程)與 =(結構欄位形狀)之間的區別。
定值 — 不可變繫結#
定值 繫結只能寫入一次。宣告時可以提供初始值,也可以不提供;若未提供初始值,則必須在讀取前恰好指派一次。第二次指派會被拒絕。
入口 {
定值 整數 count ← 0
定值 文字 name ← "Marcus"
定值 _ inferred ← [1, 2, 3]
}延遲初始化:
入口 {
定值 整數 factor
若 真 {
factor ← 10
}
否則 {
factor ← 100
}
註記 factor
}變值 — 可變繫結#
變值 繫結可以自由重新指派:
入口 {
變值 整數 count ← 0
count ← count + 1
count ← count * 2
}設為 — 推導的不可變語法糖#
設為 是 定值 _ 的語法糖——具有推導型別的不可變繫結:
入口 {
定值 _ salve ← "Salve"
定值 _ 名稱 ← "Marcus"
定值 _ x ← 42
# Deferred form
定值 _ label
label ← "deferred"
}執行期繫結與結構定義#
Faber 將多數語言合併在 = 中的概念分開:
| 字元 | 作用 | 用於 |
|---|---|---|
← | 執行期流程 | 初始繫結、重新指派、變更 |
= | 結構形狀 | 常值與中繼資料中的欄位名稱 |
類型 Point {
定值 整數 x
定值 整數 y
}
入口 {
# Runtime: ← attaches a value to a name at execution time
變值 整數 count ← 0
變值 文字 label ← "ready"
count ← count + 1
# Structural: = defines field values inside a type literal
定值 _ p ← Point { x = 10, y = 20 }
}取自 欄位擷取#
取自 將值中的欄位擷取至區域繫結:
類型 Persona {
定值 文字 名稱
定值 整數 aetas
}
入口 {
定值 _ p ← Persona { 名稱 = "Marcus", aetas = 30 }
定值 文字 名稱 ← p.nomen
定值 整數 aetas ← p.aetas
# prints "Marcus"
註記 名稱
}更新可變數值#
使用二元運算子 + 與 - 搭配執行期賦值 ←,更新可變的 整數 儲存處。兩個運算子都需要兩個運算元;它們不是後置陳述式:
入口 {
變值 整數 i ← 0
# i becomes 1
i ← i + 1
# i becomes 0
i ← i - 1
}Collections#
Faber 有數種由編譯器擁有的集合型別。它們的標準方法定義於編譯器中,而非標準函式庫。
Lista — 有序動態集合#
入口 {
定值 列表<整數> empty ← 空集
定值 _ numbers ← [1, 2, 3, 4, 5]
定值 _ names ← ["Marcus", "Julia", "Gaius"]
定值 _ nested ← [[1, 2], [3, 4]]
}使用 展開 展開:
入口 {
定值 列表<整數> a ← [1, 2, 3]
定值 列表<整數> b ← [4, 5, 6]
定值 _ combined ← [展開 a, 展開 b]
定值 _ headed ← [0, 展開 a, 99]
}主要方法:longitudo、accipe、appende、求和、primus、novissimus。
Tabula — 鍵值對映射#
入口 {
定值 表格<文字, 整數> scores ← { "alice": 10, "bob": 20 }
}Tensor — 密集固定形狀緩衝區#
入口 {
定值 張量<f32, []> scalar ← 空集
定值 張量<整數, [4]> row ← [1, 2, 3, 4] ↦ 張量<整數, [4]>
定值 整數 ∪ 無 first ← row[0]
}Tensor 語法糖(數值運算密集的程式碼):
入口 {
定值 tf32[] seed ← 空集
定值 tf32[4] lanes ← seed.由扁平建構([1.0, 2.0, 3.0, 4.0], [4])
}主要方法:forma、accipe、ponde、crea、structa、strue,以及逐元素算術、矩陣乘法(multiplicatio)和歸約(求和、productum)。
Sparsa — 稀疏固定形狀緩衝區#
入口 {
定值 稀疏<f32, [2, 3]> sparse ← 空集
sparse.ponde([0, 1], 4.0)
sparse.ponde([1, 2], 9.0)
# accipe returns the stored value, here 4.0
註記 sparse.accipe([0, 1])
# count of stored entries
註記 sparse.nonnihil()
}在密集與稀疏格式之間轉換:
入口 {
定值 tf32[2, 2] dense ← [[1.0, 0.0], [0.0, 2.0]] ↦ 張量<f32, [2, 2]>
定值 sf32[2, 2] sparse ← dense ↦ 稀疏<f32, [2, 2]>
定值 tf32[2, 2] roundtrip ← sparse ↦ 張量<f32, [2, 2]>
}Cursors — 延遲串流#
迭代器<T> 是延遲串流型別。它可以由集合迭代器、接收 檢視或產生器函式建立。使用 遍歷 取自 消費:
入口 {
定值 _ items ← [1, 2, 3]
遍歷 取自 items 定值 item {
註記 item
}
}Intervallum — 範圍#
# exclusive range: 0, 1, 2, 3, 4
遍歷 範圍 0‥5 定值 i {
註記 i
}
# inclusive range: 0, 1, 2, 3, 4, 5
遍歷 範圍 0…5 定值 i {
註記 i
}‥ 表示不包含終點的範圍;… 表示包含終點的範圍。
String and template literals#
Faber 使用分隔符語義——每種引號形式都代表不同的原始碼形狀。它們不是可互換的同義詞。
字面形式#
| 形式 | 類型 | 作用 | ||
|---|---|---|---|---|
'…' | ascii | 固定機器標記;不含 §;不含 (…) | ||
"…" | 文字 | 短 Unicode 行字串;可解析 (…) | ||
«…» | 文字 | 區塊/多行 Unicode;可解析 (…) | ||
… | forma | 擷取的範本;可擷取 (…) | ||
{ … } | JSON | 編譯期 JSON 文件 | ||
| ` | … | ` | 位元組 | 編譯期十六進位位元組 |
[ … ] | 列表<T> | Faber 清單字面值 |
字串範本套用#
Faber 使用字串範本套用來格式化文字:先寫入含有 § 佔位符的 "…" 或 «…» 字面值,再接上括號引數:
函式 greet(文字 名稱) → 文字 {
傳回 "Salve, §!"(名稱)
}
入口 {
定值 整數 pagina ← 3
定值 整數 totum ← 10
定值 文字 code ← "200"
定值 文字 label ← "OK"
定值 _ msg ← "Page § of §"(pagina, totum)
定值 _ block ← "status: § (§)"(code, label)
}主要規則:
§(U+00A7)是範本佔位符- 位置佔位符:
§0、§1、…,用於明確指定順序 - 尾端的
!選取顯示格式:"Salve, §!"(名稱) (args)尾碼是範本套用,不是函式呼叫
區塊字串#
多行區塊使用書名號 «…»:
入口 {
定值 _ sql ← «
select id, email
from accounts
»
}擷取的範本(forma)#
反引號範本會擷取文字與參數,但不進行解析。 適合用於繫結的 SQL/URL 承載內容:
入口 {
定值 整數 user_id ← 42
定值 _ query ← `select * from users where id = §`(user_id)
}內嵌 JSON#
裸露的 { … } 是內嵌 JSON:它是編譯期的 JSON 文件,不是匿名的 Faber 物件。鍵是以引號括起、並以 : 分隔的字串:
入口 {
定值 _ empty ← {}
定值 _ user ← { "name": "Marcus", "age": 30, "active": true }
定值 _ nested ← { "meta": { "version": 1 }, "tags": ["alpha", "beta"] }
}若要建構具型別的 類型,請使用型別名稱與 = 欄位形狀:
類型 Point {
定值 整數 x
定值 整數 y
}
入口 {
定值 _ p ← Point { x = 10, y = 20 }
}Nullability and optionality#
Faber 區分值中的缺失與宣告位置上的可選提供。
可為空值 — T ∪ 無#
當值可能缺失時,使用 T ∪ 無:
函式 find(文字 key) → 整數 ∪ 無 {
傳回 可空
}
函式 divide(整數 a, 整數 b) → 整數 ∪ 無 {
若 b ≡ 0 則 傳回 可空
傳回 a / b
}可選宣告槽位 — 可選#
當參數或欄位可由呼叫者或建構函式省略時,在名稱後使用 可選:
函式 connect(文字 host, 整數 port 可選) → 空值 {
}
類型 User {
定值 文字 email 可選
}借用標記可以與可選參數結合:
函式 process(從 整數 depth 可選) → 空值 {
}非空值斷言 — !#
使用 !.、![、!( 來斷言可為空值不是 無:
類型 Box {
定值 整數 ∪ 無 val
}
入口 {
定值 Box ∪ 無 maybe_name ← Box { val = 7 }
定值 _ name ← maybe_name!.val
}對 無 進行非空值斷言會在執行階段中止。
空值合併 — vel#
入口 {
定值 文字 ∪ 無 provided ← 可空
定值 _ name ← provided 或取 "default"
}未知#
未知 是頂層未知型別,用於逃生閘道與不完整的知識。它不是可為空值的機制。
Conversion and construction#
兩個重要的轉換運算子,一個用於執行期,另一個用於編譯期:
# runtime 變換
入口 {
定值 _ parsed ← "42" ↦ 整數 ⊥ 0
# static ascription
定值 整數 value ← 7
定值 _ text ← value ∷ 文字
}執行期轉換 — ↦#
使用 ↦ 進行執行期轉換,尤其適用於可能失敗的剖析或強制轉型。使用 ⊥ 提供行內復原:
入口 {
定值 文字 input ← "9"
定值 _ n ← "42" ↦ 整數 ⊥ 0
定值 _ safe ← input ↦ 整數 ⊥ 0
}由型別導向的具現化:
入口 {
定值 文字 path ← "/etc/hosts"
定值 _ lanes ← [1.0, 2.0, 3.0, 4.0] ↦ 向量<f32, 4>
定值 _ body ← 端點 'solum:lege' (path) ↦ 文字
}靜態歸屬 — ∷#
使用 ∷ 明確標註靜態型別。它是後綴運算子,並由目標型別決定:
入口 {
定值 整數 value ← 7
定值 _ x ← 7 ∷ i32
定值 _ text ← value ∷ 文字
}空值合併 — 或取#
當值為 無 時,使用 或取 進行空值合併:
入口 {
定值 文字 ∪ 無 provided_name ← 可空
定值 _ name ← provided_name 或取 "default"
}