Types and values
Data types#
Faber 拥有静态、类型优先的类型系统。每个声明都把类型放在名称之前:文本 名称,而不是 名称: 文本。类型系统涵盖标量原语、泛型集合、定宽数值、张量,以及面向 GPU 的寄存器类型。
原语类型#
| 类型 | 作用 | 示例字面量 |
|---|---|---|
文本 | Unicode 字符串 | "Salve, munde" |
窄字串 | 固定机器令牌 | '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]>
}游标 — 惰性流#
迭代器<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 使用分隔符语义 — 每种引号形式表示不同的源代码形态。它们之间不能互换。
字面量形式#
| 形式 | 类型 | 角色 | ||
|---|---|---|---|---|
'…' | 窄字串 | 固定机器令牌;无 §;无 (…) | ||
"…" | 文本 | 短 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 ∷ 文本
}空值合并 — vel#
当值为 空类型 时,使用 兜底 进行空值合并:
入口 {
常量 文本 ∪ 空类型 provided_name ← 皆无
常量 _ name ← provided_name 兜底 "default"
}