elab API

elab 包(Luna-Flow/QED/elab)是名称与内核之间的解析边界。它针对局部上下文和内核状态,把项中的每个名称一次性解析为已解析项 RTerm,其中的常量带有其内核标识;它依据状态对已解析项做类型检查;并把它们降级为内核项。它还提供带类型检查的内核项轻量构造器。它只依赖 kernel,不产生任何定理。

冻结标识背后的设计见 elab 设计说明;elab 教程逐步介绍解析和作用域变化。

上下文

ElabCtx

ElabCtx 是局部上下文:由变量名及其类型组成的有序列表,最内层在最后。

pub struct ElabCtx {
  locals : Array[(String, @kernel.HolType)]
}

empty_elab_ctx、elab_ctx_from_locals 和 elab_ctx_extend

这些函数用于构造上下文。elab_ctx_extend 返回多一个局部变量的新上下文;参数本身不会改变。

pub fn empty_elab_ctx() -> ElabCtx
pub fn elab_ctx_from_locals(Array[(String, @kernel.HolType)]) -> ElabCtx
pub fn elab_ctx_extend(ElabCtx, String, @kernel.HolType) -> ElabCtx

同名的后一个局部变量会遮蔽前一个。

已解析项

ResolvedConst

ResolvedConst 是在解析时冻结的常量出现。

pub struct ResolvedConst {
  name : String
  const_id : Int
  inst_ty : @kernel.HolType
  schema_ty : @kernel.HolType
}

const_id 是名称所解析到的内核标识,schema_ty 是当时声明的模式(schema),inst_ty 是此次出现的类型,即 schema_ty 的一个实例。内置等号的 const_id == -1,其模式为 α→α→bool\alpha \to \alpha \to \mathit{bool}。

RTerm

RTerm 是已解析项:其中每个常量都是 ResolvedConst 的具名项。

pub enum RTerm {
  RVar(String, @kernel.HolType)
  RConst(ResolvedConst)
  RComb(RTerm, RTerm)
  RAbs(String, @kernel.HolType, RTerm)
}

rterm_var、rterm_const、rterm_comb 和 rterm_abs

这些函数不加检查地构造已解析项。

pub fn rterm_var(String, @kernel.HolType) -> RTerm
pub fn rterm_const(ResolvedConst) -> RTerm
pub fn rterm_comb(RTerm, RTerm) -> RTerm
pub fn rterm_abs(String, @kernel.HolType, RTerm) -> RTerm

rconst_name、rconst_id、rconst_inst_ty 和 rconst_schema_ty

这些函数读取 ResolvedConst 的字段。

pub fn rconst_name(ResolvedConst) -> String
pub fn rconst_id(ResolvedConst) -> Int
pub fn rconst_inst_ty(ResolvedConst) -> @kernel.HolType
pub fn rconst_schema_ty(ResolvedConst) -> @kernel.HolType

rterm_eq

rterm_eq 是已解析项的结构相等,包括绑定名称和常量标识。它不是 α 等价。

pub fn rterm_eq(RTerm, RTerm) -> Bool

rterm_collect_free_vars 和 rterm_collect_consts

rterm_collect_free_vars 按出现顺序列出已解析项的自由变量,允许重复。rterm_collect_consts 列出每一个常量出现。

pub fn rterm_collect_free_vars(RTerm) -> Array[(String, @kernel.HolType)]
pub fn rterm_collect_consts(RTerm) -> Array[ResolvedConst]

rterm_to_string

rterm_to_string 渲染已解析项;常量打印为 RConst(name#id : inst <= schema)。

pub fn rterm_to_string(RTerm) -> String

解析

elab_resolve_name

elab_resolve_name(state, ctx, name) 解析一个名称:若 ctx 中有该局部变量则取之,否则取 state 中可见的常量,类型为其模式类型。局部变量优先于常量。

pub fn elab_resolve_name(@kernel.KernelState, ElabCtx, String) -> Result[RTerm, ElabError]

当名称既不是局部变量也不是常量时,以 UnknownName(name) 失败。

elab_resolve_const、elab_resolve_const_by_name 和 elab_resolve_const_instance

这些函数解析常量。elab_resolve_const(state, name, ty) 解析类型为 ty 的出现;elab_resolve_const_by_name 使用模式类型;elab_resolve_const_instance 把结果包装为 RConst。

pub fn elab_resolve_const(@kernel.KernelState, String, @kernel.HolType) -> Result[ResolvedConst, ElabError]
pub fn elab_resolve_const_by_name(@kernel.KernelState, String) -> Result[ResolvedConst, ElabError]
pub fn elab_resolve_const_instance(@kernel.KernelState, String, @kernel.HolType) -> Result[RTerm, ElabError]

名称 = 总是解析为内置等号。失败情形:未声明任何常量时为 UnknownConst(name),类型不是模式的实例时为 InvalidConstInstance(name),状态的标识表与模式表不一致时为 ScopeResolutionMismatch。

elab_resolve_var

elab_resolve_var 不查询上下文,直接构造已解析变量。

pub fn elab_resolve_var(String, @kernel.HolType) -> RTerm

elab_resolve_app、elab_resolve_abs 和 elab_resolve_eq

这些函数由已解析的部分构造应用、抽象或等式,并依据状态和上下文对结果做类型检查。

pub fn elab_resolve_app(@kernel.KernelState, ElabCtx, RTerm, RTerm) -> Result[RTerm, ElabError]
pub fn elab_resolve_abs(@kernel.KernelState, ElabCtx, String, @kernel.HolType, RTerm) -> Result[RTerm, ElabError]
pub fn elab_resolve_eq(@kernel.KernelState, ElabCtx, RTerm, RTerm) -> Result[RTerm, ElabError]

结果类型错误时,它们以 CoreTypingFailure 失败。对于 elab_resolve_abs,函数体在加入绑定子后的 ctx 中检查。

elab_resolve_named_term 和 elab_roundtrip_term

elab_resolve_named_term(state, ctx, t) 解析一个已有的内核项:自由变量必须是 ctx 中类型相同的局部变量,常量则按名称在 state 中重新查找。elab_roundtrip_term 还会把结果降级,并检查它与 t α 等价(包括常量标识)。

pub fn elab_resolve_named_term(@kernel.KernelState, ElabCtx, @kernel.Term) -> Result[RTerm, ElabError]
pub fn elab_roundtrip_term(@kernel.KernelState, ElabCtx, @kernel.Term) -> Result[RTerm, ElabError]

当 t 中的某个常量现在解析到另一个标识时,elab_roundtrip_term 以 ScopeResolutionMismatch 失败;正是借此可以在发生遮蔽声明之后检测出在某个作用域中构造的项。

test "resolve" {
  let a = @kernel.mk_tyvar("A")
  let st = @kernel.ks_add_const(@kernel.empty_kernel_state(), "c", a).unwrap()
  let ctx = @elab.elab_ctx_from_locals([("x", a)])
  let x = @elab.elab_resolve_name(st, ctx, "x").unwrap()
  let c = @elab.elab_resolve_name(st, ctx, "c").unwrap()
  inspect(@elab.rterm_to_string(c), content="RConst(c#1 : A <= A)")
  let eq = @elab.elab_resolve_eq(st, ctx, x, c).unwrap()
  inspect(@elab.elab_check_core_type(st, ctx, eq, @kernel.bool_ty()), content="true")
  inspect(@elab.elab_resolve_name(st, ctx, "nope") is Err(@elab.UnknownName("nope")), content="true")
  // a local named like a constant wins
  let ctx2 = @elab.elab_ctx_extend(ctx, "c", @kernel.bool_ty())
  inspect(@elab.elab_resolve_name(st, ctx2, "c") is Ok(@elab.RVar("c", _)), content="true")
}

核心类型检查

elab_core_type_of、elab_check_core_type 和 rterm_well_formed

elab_core_type_of(state, ctx, t) 计算已解析项的类型。变量必须是 ctx 中类型相同的局部变量;常量在 state 中必须仍具有相同的标识和模式,且其类型必须是该模式的实例。elab_check_core_type 把结果与期望类型比较,rterm_well_formed 测试类型是否存在。

pub fn elab_core_type_of(@kernel.KernelState, ElabCtx, RTerm) -> @kernel.HolType?
pub fn elab_check_core_type(@kernel.KernelState, ElabCtx, RTerm, @kernel.HolType) -> Bool
pub fn rterm_well_formed(@kernel.KernelState, ElabCtx, RTerm) -> Bool

核心类型检查从不重新查找名称:若冻结的标识已不是当前生效的标识,类型检查就会失败,而不会改用新的常量。

降级

elab_lower_to_term 和 elab_lower_to_db

elab_lower_to_term 把已解析项转为内核项,保留每个常量标识;elab_lower_to_db 则进一步转为内核的 De Bruijn 形式。

pub fn elab_lower_to_term(RTerm) -> Result[@kernel.Term, ElabError]
pub fn elab_lower_to_db(RTerm) -> Result[@kernel.DbTerm, ElabError]

当降级后的项类型错误或无法转换时,两者都以 CoreTypingFailure 失败。

test "freeze" {
  let bool = @kernel.bool_ty()
  let st1 = @kernel.ks_add_const(@kernel.empty_kernel_state(), "c", bool).unwrap()
  let ctx = @elab.empty_elab_ctx()
  let c1 = @elab.elab_resolve_name(st1, ctx, "c").unwrap()
  // a shadowing declaration in an inner scope
  let st2 = @kernel.ks_add_const(@kernel.ks_push_scope(st1), "c", bool).unwrap()
  inspect(@elab.rterm_well_formed(st1, ctx, c1), content="true")
  inspect(@elab.rterm_well_formed(st2, ctx, c1), content="false")
  // the lowered term keeps the identity resolved in st1
  let t = @elab.elab_lower_to_term(c1).unwrap()
  inspect(@kernel.term_to_string(t), content="Const(c#1 : bool)")
  inspect(@elab.elab_roundtrip_term(st2, ctx, t) is Err(@elab.ScopeResolutionMismatch), content="true")
}

内核项构造器

这些函数带类型检查地直接构造内核 Term 值,供不需要已解析项的调用者使用。

elab_var、elab_const 和 elab_const_instance

elab_var 即 mk_var。elab_const 和 elab_const_instance 分别是 ks_mk_const 和 ks_mk_const_instance。

pub fn elab_var(String, @kernel.HolType) -> @kernel.Term
pub fn elab_const(@kernel.KernelState, String) -> Result[@kernel.Term, @kernel.SigError]
pub fn elab_const_instance(@kernel.KernelState, String, @kernel.HolType) -> Result[@kernel.Term, @kernel.SigError]

elab_app、elab_app2、elab_abs 和 elab_eq

这些函数构造应用(一个或两个参数)、抽象或等式,结果类型错误时以 TypeMismatch 失败。

pub fn elab_app(@kernel.Term, @kernel.Term) -> Result[@kernel.Term, @kernel.LogicError]
pub fn elab_app2(@kernel.Term, @kernel.Term, @kernel.Term) -> Result[@kernel.Term, @kernel.LogicError]
pub fn elab_abs(String, @kernel.HolType, @kernel.Term) -> Result[@kernel.Term, @kernel.LogicError]
pub fn elab_eq(@kernel.Term, @kernel.Term) -> Result[@kernel.Term, @kernel.LogicError]

elab_is_prop 和 elab_require_prop

elab_is_prop 测试一个项是否为类型良好的命题。elab_require_prop 返回该项,否则以 NotBoolTerm 失败(项类型错误时为 TypeMismatch)。

pub fn elab_is_prop(@kernel.Term) -> Bool
pub fn elab_require_prop(@kernel.Term) -> Result[@kernel.Term, @kernel.LogicError]
test "builders" {
  let a = @kernel.mk_tyvar("A")
  let f = @elab.elab_var("f", @kernel.fun_ty(a, @kernel.bool_ty()))
  let x = @elab.elab_var("x", a)
  let fx = @elab.elab_app(f, x).unwrap()
  inspect(@elab.elab_is_prop(fx), content="true")
  inspect(@elab.elab_app(x, f) is Err(@kernel.TypeMismatch), content="true")
  inspect(@elab.elab_require_prop(x) is Err(@kernel.NotBoolTerm), content="true")
}

错误

ElabError

ElabError 是解析和降级的错误类型。

pub enum ElabError {
  UnknownName(String)
  UnknownConst(String)
  InvalidConstInstance(String)
  ScopeResolutionMismatch
  CoreTypingFailure
}
构造子含义
UnknownName(name)该名称既不是局部变量,也不是可见常量。
UnknownConst(name)没有声明过此名称的常量。
InvalidConstInstance(name)所请求的类型不是该常量模式的实例。
ScopeResolutionMismatch冻结的标识与状态不再匹配,或状态的各表互相不一致。
CoreTypingFailure已解析项在当前状态和上下文中类型错误。

elab_err_unknown_name、elab_err_unknown_const、elab_err_invalid_const_instance、elab_err_scope_resolution_mismatch 和 elab_err_core_typing_failure

这些谓词测试某个 ElabError 是哪个构造子,供偏好函数而非模式匹配的调用者使用。

pub fn elab_err_unknown_name(ElabError) -> Bool
pub fn elab_err_unknown_const(ElabError) -> Bool
pub fn elab_err_invalid_const_instance(ElabError) -> Bool
pub fn elab_err_scope_resolution_mismatch(ElabError) -> Bool
pub fn elab_err_core_typing_failure(ElabError) -> Bool