程序其实是一台机器的“描述”, 而我们需要做的就是让这台机器运转起来,
机器运行的前提条件就是需要“数据”, 然后让数据"流动"起来,在流动的过程中对数据进行变化与操作。
- 值
- 表达式
- 变量
- 语句
- 函数: 这里的函数包含了元函数
- 函数调用
有了上面的基础组件, 下面就是让这些基础组件组合起来的组合组件
9. 赋值操作: 表示让让一个数据流向变量, 形式化的操作是这样: a <- 1
10. 函数传参: 比如(+ 1 2)
, 表示让一个数据从函数外部流向函数内部
11. 函数体: 函数体描述了整个函数如何计算函数的输出
12. 函数返回值: (fun ([:a Int] [-> b]))
,表示让一个数据从函数内部流向外部
有了上面的两大模块, 下面就是将它们放到整个执行系统中遵循特定的规则进行执行
- 变量引发环境中的相关操作
- 赋值操作的左手性和右手性
- 函数执行, 函数执行的结果
- 函数执行后的资源释放
变量是作为表达式的求值的另外一种表示, 也就是这样:
var a = 2 + 3;
var a = new Person();
当我们使用声明语句声明一个变量的时候, 就意味着下面这两件事情:
- 首先在当前环境(一种数据结果)中登记一个名字
- 其次我们可以在编译期间发现这个名字
上面我们提到了环境这一个概念, 设计环境的概念的目的是解决存在名字和资源管理的问题
- 相同作用域出现相同名称的变量
- 静态作用域, 形成函数闭包
- 当进入一个环境的时候我们记录下名字
- 当退出一个环境的时候我们将会清理环境中的资源
赋值操作的含义是将值与标识符进行关联起来, 常见的编程语言都采用等号来作为赋值操作, 等号的右手端是一个值, 这个值可以来自于表达式的求值结果, 左手端只是一个引用, 因为在一些编程语言中你可以写出下面这样的代码:a.x=1+2
函数调用有两个语法组件, 分别是操作和操作数
var sq = x => x * x;
sq(3);
(x=>x*x)(3)
- 首先将实际参数与形式参数一一比对
- 其次将函数体中的形式参数进行替换
函数的参数只是一个标签, 它只在函数内部可见, 在函数外部完全是不可见的
编译原理:
如何编码数据, 编码计算过程, 我们将会使用计算图来进行编码, 计算图的本质就是一颗AST树