“[2] Robert Harper,Practical Foundations for Programming Languages,2nd ed.,2016,Chapter 1 “Abstr…”
“变量绑定已经规定哪些出现属于哪个声明。本页实现这一关系:输入是带源位置的AST,输出把每个声明和变量使用都标成唯一声明 ID 的 resolved AST,或给出未绑定名称错误。它不执行程序…”
定义Definition
施工中 · 内容逐步修订
Variable binding · Binding occurrence
把变量的使用出现关联到作用域内声明,并区分自由出现、绑定出现与遮蔽。
变量绑定是在抽象语法的出现位置之间建立的关系。一个绑定器声明变量名并确定作用域;作用域内每个同名使用出现,若没有先遇到更内层的同名绑定器,就由该声明绑定。没有关联到任何绑定器的出现称为自由出现。
以无类型 λ 项
为例,
若
程序语言中的函数参数、let 声明、模式变量、类型变量和异常处理器都可按“绑定器—作用域—使用出现”分析。每种构造必须单独规定作用域;例如非递归 let x=e_1 in e_2 的
变量名像连线旁的标签,绑定结构才说明一次使用取哪个声明的值。内层声明会遮蔽外层同名声明;只要改名同时更新它所绑定的全部出现,连线不变,项的绑定含义也不变。
把语法画成树时,每个绑定变量的使用节点都有一条回边指向其声明节点,自由出现则没有这样的回边。解析一个使用时,从该节点向外寻找最近的同名绑定器;找到后就停止,不再让更外层声明接管。普通树边给出作用域嵌套,回边给出名称解析。文本搜索只看标签,看不到回边,因而会在重命名、替换或宏展开时制造捕获。
在
项
新名字还必须避免捕获。例如
闭项与值也不等同。
本页默认词法作用域:绑定由源语法嵌套决定。动态作用域改按运行时调用链寻找声明,同一函数体中的名字可能随调用者改变含义,不能直接套用上述静态回边。未经卫生处理的宏也可能把展开后落入作用域的名字意外重新绑定。
绑定结构是α-等价与无捕获替换的共同基础。前者忽略绑定标签而保留回边,后者移动子树时保持自由出现不被新绑定器接管。
编译器的名称解析把表面名字解析成符号表条目,随后可用唯一标识符或 de Bruijn 索引表示绑定。环境语义则把自由变量的解释交给环境;函数值若需保存定义处环境,就形成闭包。这些表示改变名称管理方式,不改变词法绑定应满足的关系。
类型系统把同一结构推广到类型变量和上下文。类型环境记录变量可用的类型或类型方案,运行时环境记录值;二者都处理作用域,却不能混作同一种映射。依赖类型与模块系统还会让绑定跨越项、类型与命名空间。
词法绑定的定义可由静态名字解析具体实现为声明唯一 ID、按名字的栈及作用域恢复。该算法把每次使用固定到某个声明,并以非递归 let 右侧与未绑定诊断检验实现;它不改变本页关于自由出现和遮蔽的关系定义。