Skip to content

Latest commit

 

History

History
657 lines (466 loc) · 16.6 KB

File metadata and controls

657 lines (466 loc) · 16.6 KB

LSR 000 - Lamina 核心语言规范(草案)

1. 语言定位

Lamina 是静态强类型、表达式导向的数学 DSL/脚本语言,支持单位系统、代数表达和局部类型推导。

2. 核心关键字

let, var, const, unit, func, return, in, not, loop, while, break, continue, if, else, match, sym, import, use, as, and, or

3. 运算符总览

3.1 基础算术与优先级

  • 算术运算符:+, -, *, /, %, ^
  • 优先级(高到低):
    1. ^
    2. *, /, %
    3. +, -

3.2 逻辑与比较

  • 标量比较:==, !=, <, <=, >, >=
  • 广播比较:.==, .!=, .<, .<=, .>, .>=
  • 逻辑:and, or, not
  • 规则:逻辑运算优先级低于算术运算
  • 规则:未加点的比较仅用于标量;vector/matrix 比较必须使用加点算子
  • 优先级(高到低, 低于3.1运算符):
    1. or, and
    2. ==, !=
    3. >, <, >=, <=

3.3 赋值与绑定

  • 赋值:=
  • 绑定:let(只读),var(可变)
  • 符号声明:sym(类型固定为 Expr
  • 优先级:最低

3.4 矩阵与向量运算符

  • 线性代数:*, \\, /, ^
  • 元素广播:.*, ./, .+, .-, .^
  • 关系广播:.==, .!=, .<, .<=, .>, .>=
  • 转置:'(共轭转置),.'(非共轭转置)
  • 优先级: 线性代数暂定,元素广播同3.1,关系广播同3.2

3.5 集合相关运算符

  • 从属:in, not in
  • 子集:subset
  • 并交差:|, &, -
  • 对称差:xor

3.6 函数与流程运算符

  • Lambda 箭头:->
  • match 分支箭头:=>
  • 管道:|>

3.7 运算符分派与歧义约束

运算符 仅适用类型 语义 歧义处理
/ num 数值除法 若操作数不满足数值或矩阵规则,编译报错
\\ matrix 矩阵左除(解 A X = B 左值必须可作为系数矩阵,维度不匹配或系统无解时报错
/ matrix 矩阵右除(解线性系统) 左值必须是矩阵,右值可用于右除,否则报错
^ num / Expr 幂运算 集合对称差使用 xor
^ matrix 矩阵幂(整数指数) 非方阵或非整数指数报错
xor set 集合对称差 集合对称差统一使用 xor
< <= > >= == != 标量(num/complex/text/bool 标量关系比较 操作数为 vector/matrix 时编译报错,要求使用加点比较
.* ./ .+ .- .^ vector/matrix 与标量或同形状容器 元素级广播 / 哈达玛运算 维度不兼容报错
.== .!= .< .<= .> .>= vector/matrix 与标量或同形状容器 元素级关系广播 返回同形状 vector<bool>/matrix<bool>,维度不兼容报错

4. 变量、类型与推导

4.1 类型系统

具备自底向上类型推导,多数情况推荐手动标注类型

4.2 局部类型推导规则

  • 允许推导:局部 let/var 绑定、for 推导式局部变量
  • 必须显式:函数参数类型、函数返回类型、模块导出符号类型
  • Lambda 与 match 的推导规则由 LSR-006 与 LSR-005 定义
  • 推导结果必须为确定类型;约束不足时编译报错

4.3 声明语法

变量声明统一 let|var|const name type = expr 或者 let|var|const name = expr

  • let:只读绑定, 当绑定为对象类型时,仅代表不可再次绑定另一个对象|值,而不是对象本身不可变
  • var:可变绑定
  • const:编译期常量声明(只读,要求初始化表达式可在编译期求值)
let a = 10
let pi_val real = 3.1415
let fraction = 3/2
const TAU = 2 * pi

let c = 5/4
let name = "LSR"

var counter = 0
counter = counter + 1

a = 20   # 编译报错

4.4 核心数据类型

类型 说明 字面量 / 示例
num 数值超集(int, real, frac 42, 114.514, 1/2
null 空类型,既是类型也是值
complex 复数 3 + 4i
text 文本 "i love lamina"
bool 布尔逻辑 true, false
set 无序去重集合 {1,2,3}
vector 一维同构数值数组(1 索引) vec[1,2,3]
table 哈希表(任意可哈希键) 见 4.5
matrix 二维同构数值网络(1 索引) mat[1,2;3,4]
Expr CAS 符号表达式 x^2 + 1
  • 在当前定义中,int, bool, null为值类型,其他为对象引用类型

4.5 table 万能表规范

table 是键值容器,逻辑类型记作 table<K, V>

  • K 必须是可哈希类型, 单个表支持多种不同可哈希键类型
  • V 可为任意类型(可包含 numtextvectormatrixExpr 等)
  • 这会是你在LSR中看到的最动态类型的容器

4.5.1 字面量与创建

字面量语法使用 table{key => value, ...}

let empty_tbl = table{}
let scores = table{"alice" => 98, "bob" => 87}
let mixed_val = table{"v" => vec[1,2], "m" => mat[1,2;3,4]}

类型推导规则(暂不做数,待定):

  • 空表需在后续写入中确定 KV,若约束不足则编译报错
  • 非空字面量中,所有 key 必须可统一到同一 K
  • value 统一到同一 V;数值类型允许按数值塔提升

4.5.2 键类型约束

默认可哈希键类型:complextext

默认键类型范围仅包含:complextextbool。其他类型作为键需包含.hash()子方法。

不支持num键类型的原因: 支持朴素标识符键类型,编译时哈希

let comping_hash_table = table{
  animal => "dog", num => "1"
} //这部分通常不可遍历

4.5.3 读取与缺失键行为

读取语法:tbl[key]

let scores = table{"alice" => 98, "bob" => 87}
let a = scores["alice"]

键规则:

  • 直接读取 tbl[key] 且键不存在时,返回null
  • 写入键必须可哈希,否则runtime报错

4.5.4 更新与写入

写入语法:tbl[key] = value,包括覆盖与新增。

var scores = table{"alice" => 98}
scores["alice"] = 100   # 覆盖
scores["bob"] = 91      # 新增

4.5.5 常用查询操作

scores.has("alice")        # bool
scores.keys()              # vector<K>
scores.values()            # vector<V>
scores.items()             # vector<(K, V)>

4.6 复合类型的值语义与引用语义

4.6.1 总规则

  • 复合类型实现采用共享引用,降低拷贝成本
  • 可观察语义采用写时复制(COW)
  • 只读操作(读取、遍历、计算)不触发复制
  • 一旦发生可变写入(var 绑定上的突变),若对象被共享,必须先分离副本再写入

4.6.2 赋值语义

  • 赋值后两个变量指向同一底层对象(is 可能为 true
  • 对其中一个变量做可变写入时,触发 COW,另一个变量保持原值
var t1 = table{"x" => 1}
var t2 = t1

t2["x"] = 9

# COW 后可观察结果
# t1["x"] == 1
# t2["x"] == 9

4.6.3 函数传参语义

  • 非值类型参数采用引用传递
  • 函数内对局部可变绑定突变时,按 COW 分离
  • 修改结果通过 return 新对象交付调用方
func bump(src table) -> table {
    var t = src
    let v = t["n"]  # 若为值类型则产生复制,否则为引用
    if v != null {
        t["n"] = v + 1
    }
    t
}

var a = table{"n" => 0}
var b = a |> bump()

# a["n"] == 0
# b["n"] == 1

4.6.4 与 let/var 的关系

  • let:只读绑定,COW 写路径仅由 var 触发
  • var:可变绑定,触发 COW 规则
  • 本规则统一适用于 vectormatrixtableset

4.7 容器齐次性约束

vectormatrix 强齐次,保证类型稳定与 BLAS 友好。

  • vector<T> 要求所有元素类型一致
  • matrix<T> 要求所有元素类型一致
  • 对数值容器,元素量纲签名也必须一致

示例:

let ok_v = vec[1<m>, 2<m>, 3<m>]          # 合法:同类型同量纲
# let bad_v = vec[1<m>, 2<s>]             # 非法:量纲不一致

异构数据建议:

  • 需要混合不同量纲(如 [pos, vel])时,使用 table
  • 或使用后续结构体规范(若引入)

5. 量纲系统

5.1 声明与运算

单位通过尖括号 <> 附加于数值后形成复合类型。编译器执行量纲代数(约分、乘除)与加减一致性检查。

let dist = 10<m>
let time = 2<s>
let spd = dist / time

# let error = 5<m> + 2<s>   # Dimensional Mismatch

5.2 显式单位转换

单位转换必须使用 as

let v = 20<m/s>
let v_kmh = v as <km/h>

5.2.1 用户自定义单位

用户可使用 unit 声明新单位,支持两种形式:

  • 抽象基单位:unit U
  • 派生单位:unit V = expr<...>
unit score
unit token

unit km = 1000<m>
unit min = 60<s>
unit N = 1<kg*m/s^2>
unit level = 100<score>

约束:

  • 单位名在当前命名空间内唯一
  • 单位定义要求无环(如 unit a = 2<b>unit b = 3<a> 形成环)
  • 抽象基单位可直接创建;派生单位需可归约到已知单位组合(SI 或抽象基单位)
  • 派生单位必须可归约到已知单位组合(SI 或已声明抽象单位)
  • 定义成功后可参与 as <...> 转换(仅限同量纲)

5.3 底层表示

  • 量纲签名在编译期类型检查阶段表示为“SI 七维 + 用户基单位”的稀疏指数映射
  • 无量纲纯数字对应零向量
  • 乘除运算对应向量加减
  • 相同量纲不同缩放单位仅允许通过 as 显式转换

实现约束:

  • 运行期普通数值不携带量纲元数据
  • Codegen 阶段应抹除量纲标签,退化为原生数值(如 float64/int
  • 以便复用 BLAS/LAPACK 等高性能线代后端
  • Expr(CAS)允许保留量纲符号,用于符号推导中的一致性验证

5.4 量纲剥离(to scalar)

带量纲值剥离为纯数值的语法与边界由 LSR-008 定义。

let dist = 10<m>
let raw = dist as num              # SI 基准转换后剥离
let raw_keep = dist as scalar      # 仅剥离标签,保持当前刻度

let speed = 20<m/s>
let raw_kmh = (speed as <km/h>) as num

规则:

  • 默认剥离到 num 使用 SI 基准量值
  • as scalar 仅移除量纲标签,不进行数值缩放
  • 若需要特定单位下的纯数值,先做单位转换再剥离
  • as num<_> 在新规范中非法,必须使用 as num

6. 函数

6.1 函数签名

函数签名语法:func name(param Type, ...) -> ReturnType

func kinetic_energy(m num<kg>, v num<m/s>) -> num<J> {
    return 1/2 * m * v^2
}

func second2hour(s num<s>) -> num<h> {
    return ((s as num) / 3600) as num<h>
}

6.2 Lambda 与 match 的规范边界

  • 本文件不定义 Lambda 语法与类型推导细则
  • Lambda 的语法、类型推导、与管道交互由 LSR-006 单独定义
  • match 的语法、穷尽检查、模式系统由 LSR-005 单独定义

7. 控制流与推导式

7.1 表达式化 if

if 是表达式,必须有 else(或提前 return 完全覆盖)。

let abs_val = if x < 0 {
    -x
} else {
    x
}

7.2 loop 定次循环

loop x { ... } 表示循环体执行 x 次。x 必须是可确定为非负整数的表达式。

loop 5 {
    print("tick")
}

let n = 3
loop n {
    counter = counter + 1
}

规则:

  • 循环次数在进入循环前求值一次
  • x == 0,循环体不执行
  • x < 0 或不是整数,编译报错

7.3 while 条件循环

while cond { ... }condtrue 时重复执行循环体。

var i = 0
while i < 5 {
    i = i + 1
}

规则:

  • 每轮迭代前重新计算 cond
  • cond 必须是 bool 类型,否则编译报错
  • 支持 breakcontinue

7.4 for 迭代与推导式

迭代:for 名字 in 可迭代对象 {...}

不论迭代还是推导式,其可迭代对象必须包含 begin() next(last iterator)end()子方法

let person = vec[2,4,32,5,6]
for num in person { 
  print(num)
}

# 等价写法:

let person = vec[2,4,32,5,6]
{
  let end = person.end()
  var iter = person.begin()
  var num = iter.get()
  while iter != end {

      print(num)

      iter = person.next(iter)
      num = iter.get()
  } 
}

推导式语法:表达式 for 变量 in 可迭代对象 if 守卫条件

# 向量推导
let squares = vec[x^2 for x in range(1, 10) if x % 2 == 0]

# 集合推导
let abs_set = {abs(x) for x in vec[-1, 1, 2, -2]}

# 矩阵推导
let M = mat[i * j for i in range(1,3); for j in range(1,3)]

规则:

  • 推导式内部为独立词法作用域
  • 外部变量访问范围:读取外部 let;外部 var 通过显式返回更新
  • 迭代器单次求值

8. 向量与矩阵计算

8.1 定义、拼接与索引

let A = mat[1,2,3;4,5,6;7,8,9]
let v = vec[1,2,3]

let A_double = [A, A]
let A_stack = [A; A]
let element = A[2,3]

8.2 切片

let row2 = A[2,*]
let col3 = A[*,3]
let submat = A[1..2,2..3]

8.3 算术与关系广播定义

  • 标准线性代数算子:*, \\, /, ^
  • 元素广播算子:.*, ./, .+, .-, .^
  • 关系广播算子:.==, .!=, .<, .<=, .>, .>=
  • \\/ 分别定义为左除与右除:A \\ BA X = BB / AX A = B
  • \\/^ 采用按类型分派;无法唯一分派时编译报错
  • 未加点的关系比较仅用于标量;容器比较必须使用加点算子
let X = A \\ B      # 线性系统 A X = B
let Y = B / A       # 线性系统 Y A = B
let B = A .+ 10
let C = A .* A
let D = A * A   # A 必须为方阵

let flags = vec[1,2,3] .> 1      # vec[false, true, true]
# vec[1,2,3] > 1                 # 编译报错(容器比较需使用 .>)

8.4 常用操作

dot(v1, v2)      # 点积
cross(v1, v2)    # 叉积(3维)
norm(v)          # 范数
v1 .+ v2         # 逐元素加法
v .* 2           # 标量广播
matmul(A, v)     # 矩阵-向量乘
matmul(A, B)     # 矩阵-矩阵乘
inv(A)           # 逆矩阵
det(A)           # 行列式

9. 集合与逻辑

运算符 含义 示例
in / not in 元素从属 2 in {1,2,3}
subset 子集关系 {1,2} subset {1,2,3}
` , &, -, xor` 并、交、差、对称差

预定义数学常量:pi, e, phi

预定义集合:{R}, {Z}, {Q}, {C}

10. 数值塔与提升规则

层级:Z ⊂ Q ⊂ R ⊂ C ⊂ Expr

  • Int (Z):大整数,与 int 区别在于其为无限精度
  • Fraction (Q):分数(分子分母均为 Int), 与 frac 区别在于 frac 分子分母均为 int
  • Real (R):实数
  • Complex (C):复数
  • Expr:符号表达式

提升规则:

  1. 二元运算中,低层级自动提升到高层级
  2. Expr 降级需显式转换
  3. 除法只有在显式涉及 Real 时返回 Real
  4. 数值提升与单位推导互不干涉
let a = 2 + 1/2
let b = 1/2 + 0.5
let c = 2.0 + 3i

sym x
let d = 5/2 + x

11. Expr 边界与求值

Expr 为延迟求值 AST;参与数值运算时整体提升为 Expr

let c = 5
sym x
let res = c * x

Expr 降级必须显式:

  1. 代入求值:expr(symbol => value)
  2. 强制浮点:evalf(expr)
sym x, y
let equation = x^2 + 1 + y*2
let val1 = equation => (x => 3, y => 4)

let exact = sin(pi / 4)
let approx = evalf(exact)

12. 相等性语义

  • 结构相等:==
  • 数学等价(仅 Expr):===(由 LSR-007 单独定义)
let a = vec[1,2,3]
let b = a
b is a   # true

let c = vec[1,2,3]
c is a   # false

vec[1,2,3] == vec[1,2,3]   # true
[1,2;3,4] == [1,2;3,4]     # true

13. 序列与模块系统

13.1 序列生成

func square(x num) -> num {
    return x^2
}

let nums = range(1,10)
let squares = nums |> map(square)
range(start int, end int) -> vector

13.2 命名空间与模块

import:加载模块并绑定模块对象。
use:从模块导入符号到当前作用域(冲突时报错)。

import std.math
import physics.quantum

let val = math.sin(math.pi / 2)

use std.math.{sin, cos, pi, e}
use std.linalg.{det}

let wave = sin(pi * x) + cos(e * x)
let D = det(matrix_A)

use std.constants.{G as GRAVITY}

14. 关联文档

  • LSR-003:Lamina C 扩展与插件规范
  • LSR-004:标准库规范(模块结构、数学系统、库调用约定)
  • LSR-005:match 规范(语法、穷尽检查、模式系统)
  • LSR-006:Lambda 规范(语法、类型推导、管道交互)
  • LSR-007=== 数学等价规范(判定边界与化简策略)
  • LSR-008:量纲剥离规范(as num 语义、边界与错误模型)