从名字开始:变量和 let
本节阅读量:写第二章代码之前,先把语言范围说清楚。
第一章的表达式只有两种:
|
|
第二章增加两种:
|
|
也就是说,本章仍然是“一个程序就是一个表达式”,只是表达式种类更多了。
变量引用
变量是源码里的名字,例如:
|
|
变量引用本身不保存值。它只是说:
|
|
这个程序可以得到 40:
|
|
因为 body 里的 x 可以看到外层 let 建立的绑定。
但这个程序会报错:
|
|
语法上它是一个合法变量引用;求值或编译时才会发现没有任何地方绑定了 x。
let 表达式
本章的 let 写成:
|
|
它由六个小块组成:
|
|
可以读成:
|
|
所以:
|
|
结果是:
|
|
value 先在旧环境里求值
let 的 value 也可以是表达式:
|
|
先算 value:
|
|
再用扩展后的环境求 body:
|
|
这里有一个容易写错的规则:
|
|
内层 let 的 value 是:
|
|
这个 value 要在旧环境里求值,所以这里的 x 仍然是外层的 1。算出 2 以后,内层 body 里的 x 才绑定到新的 2。
同名遮蔽
如果内层又绑定同名变量,内层绑定会暂时遮住外层绑定:
|
|
内层:
|
|
结果是 32。
离开内层以后,外层 x 仍然是 10。所以整个程序是:
|
|
这叫 shadowing。它不是修改外层变量,而是在更小的范围里建立了一个新的同名绑定。
写成规则
第二章的表达式规则是:
|
|
本章先把 identifier 规则定得很简单:
|
|
所以这些名字都可以作为普通变量名:
|
|
x1、total-1、done? 这类名字暂时不支持。+ 仍然是加法操作符,不是普通变量名。
合法和非法
合法程序:
|
|
其中 x 只是语法合法;如果没有绑定,运行时仍然会报错。
非法程序:
|
|
原因也很直接:
|
|
现在已经知道第二章什么文本算合法。下一节先看 AST 怎样表示变量和 let。
本节目录