跳到主要内容

类型值(Type Values)

类型值是 JavaScript 可能值的集合的符号表示——它不像具体值 42 或 "hello" 那样只持有一个值,而是表示共享某些特征的所有值(如「任意数字」或「字面量 1」)。

类型系统是 Abs——{ shape, term?, pred?, conf }——而且它是唯一的类型系统:一个可计算的值,其约束参与代数(x > 0 ⇒ x + 1 > 1)。分析、展示与投影(.d.ts / zod / guard)全部直接消费 Abs;不存在独立的 IR,也没有有损桥接。

四个组成​

  • shape——外延载体:值长什么样。种类:prim(带 lit term 即精确值)、obj、arr、tuple、fn、eff(promise<…> / generator<…>)、brand(名义实例)、sum(联合)、never、unknown/any。
  • term——抽象值身份:lit(具体值)、var(符号 α,如 A1)或 app(应用表达式,如 (x + 2))。
  • pred——相对 term 的约束:(x + 2) > 3。
  • conf——抽象的精确度:exact / path / widened / mock / partial / opaque。

构造器(num()、strLit(…)、obj({…})…)与核心函数(leqAbs、formatAbs、checkSource…)见 core API。

字面量​

带 lit term 的 prim shape 表示恰好一个具体值——引擎从代码字面量或具体 @nudo:case 实参产出它:

25  #exact            // 精确的数字 25
"localhost" #exact // 一个特定字符串

基本类型​

不带 lit term 的 prim shape 是整个域——知道值属于该类型但不知道具体是哪个:

number   // 任意数字
string // 任意字符串
boolean // true 或 false

对象、数组、元组​

obj 携带已知槽位(每键 { value, optional? }),arr 单一元素类型,tuple 定长逐元素:

{ host: "localhost", port: 8080, debug: false }
[2, 4, 6] // 字面量元组——元素抽象时为 arr
number[] // 抽象元素

函数与 Promise​

fn 携带参数名(或 paramTypes/returnType 签名);eff 包装异步效应,小写渲染:

load: (id) => ?                      // 函数值,返回未知
promise<{ id: 7, name: "u7" }> // 异步结果

联合​

sum 是成员 Abs 的联合——值可能是任一成员:

25 | 9                // 两个精确数字(来自两个调用点)
number | string // 异构联合

never 是空集(不可达);unknown 是全集。


指令中的类型表达式​

@nudo:case / @nudo:mock / @nudo:refine 的实参用约束表达式文法书写——与 *.nudo.js 模板相同的构建器:

表达式含义示例
number() / string() / boolean()基本类型域@nudo:case "symbolic" (number())
lit(v)字面量域lit(42) / lit("ada") / lit(true)
union(…)成员联合union(lit(1), lit(2))
shape({ … })对象形状(字段递归)shape({ id: number().gt(0) })
array(…) / record(…)数组 / 记录域array(number())
fn({ … }, …)函数关系fn({ x: number().gt(0) }, number())
构建器链.gt/.gte/.lt/.lte/.shift/.int…number().gt(0).int()
裸字面量直接解析42、"abc"、true、[1, 2]

指令类型表达式使用上面的约束构建器加具体字面量。旧的 T.* 产品文法已移除。@nudo:mock body 内写普通 JavaScript 值和闭包,不要把构建器调用当作返回负载。

/**
* @nudo:case "concrete" (5, 3)
* @nudo:case "symbolic" (number(), number())
* @nudo:case "mixed" (lit(0), string())
*/
function combine(a, b) {
return a + b;
}

设计原则​

Nudo 的类型值体系遵循四条核心原则,决定运算与推断的行为。

1. 字面量保持​

所有输入都是字面量时,输出也是字面量。引擎计算出具体结果。

combine(5, 3)   // → 8  #exact,不是 number
"ab" + "c" // → "abc" #exact

信息足够时推断类型保持精确。

2. 抽象时拓宽​

任一输入抽象(非字面量)时,结果拓宽到相应域——但 Nudo 尽可能保留结构。

1 + number        // → number  #path(展示为域)
"xy" + string // → string #path(展示为域)
string + string // → string(无结构可保留)

字符串拼接涉及至少一个字面量时,Nudo 内部追踪模板字符串——已知前后缀被保留,这正是 ("user-" + x).startsWith("user-") 在符号 x 下也能折叠为 true #exact 的原因。

3. 惰性联合分布​

联合按原样传播。符号值上的运算保持符号——不会急切展开成成员笛卡尔积。这避免组合爆炸并保持相关性:

function selfAdd(a) {
return a + a; // intension: (A1 + A1)——一个符号变量,不是 A1 + A1'
}

selfAdd(1); // → 2 #exact(逐调用点)
selfAdd(2); // → 4 #exact
// Observed: 2 | 4——相关性保持,绝不会是 1+1 | 1+2 | 2+1 | 2+2

抽象实参下结果拓宽到代数判定的域(sum(number, string) → string #path;selfAdd(number) → number #widened)——只有运算符或方法必须区分成员时才逐成员展开。

4. 守卫窄化​

类型守卫在分支中窄化值。检查 typeof x === "string" 或 x === null 时,引擎在 if 分支窄化 x,在 else 分支排除这些值。

function process(x) {
if (typeof x === "string") {
// 这里 x 是 string
return x.length; // → number
}
if (x === null) {
// 这里 x 是 null
return 0;
}
// x 已窄化(如输入为 string | number | null 时是 number)
return x;
}

窄化规则支持 typeof、===、!==、instanceof、Array.isArray 与真值检查。