编程语言三要素
- 基本的表达形式,包括基本数据和基本过程
- 组合的工具,提供对过程和数据进行组合的方法
- 抽象的工具,提供对过程和数据进行抽象的方法
Lisp表达式
变量定义
(define <name> <value>)
变量定义是Lisp中最简单的抽象方法,它允许我们可以用一个简单的名称去引用一个复杂的组合运算结果,而不用重复结果的计算细节。计算结果可以通过名称去引用,这意味着解释器需要维持某种环境,用于关联名称和值
组合式
(<operator> <operands>)
组合式是Lisp表达式的一种,嵌套的组合式提供了组合多个操作的方法。其求值规则如下:
- 求值组合式的各个子表达式
- 将最左子表达式的值应用于其他子表达式,即将过程应用于相应的实际参数
条件表达式
- cond表达式
(cond (<p1> <e1>)
(<p1> <e1>)
...
(<pn> <en>))
- if表达式
(if <predicate> <consequent> <alternative>)
条件表达式求值具有短路性,这是其与组合式的根本不同
过程抽象
复合过程
(define (<name> <formal-parameter>) <body>)
过程定义是Lisp中强大的抽象方法, 它允许我们可以用一个简单的名称去引用一个复合操作单元。同变量定义一样,解释器将在环境中关联这个名称与过程定义
高阶过程
能操作过程的过程,即高阶过程,具体来说就是以过程为参数,或者以过程为返回值
高阶过程是一种强大的抽象技术,它允许我们抽象出能应用于若干不同过程的公共模式
lambda表达式
- 创建临时过程,过程定义不与环境中任何名字关联
- 创建局部变量
过程黑箱
过程定义应该隐藏其实现细节
- 形式参数名的局部化
- 子过程的局部化
过程应用
有了过程定义之后,就可以继续说明组合式求值规则第二条,即过程应用的细节了
代换模型是过程应用模型中最简单的一种,它不代表解释器的实际计算过程,其规则为将过程体中的每个参数用相应的实参取代后,对过程体求值。按照运算对象的实际求值时间,又分为应用序求值和正则序求值。
Lisp解释器使用应用序求值。
应用序求值
先求值参数而后应用
优点:
- 避免表达式的重复求值
- 可以处理更为复杂的过程应用模型
正则序求值
完全展开而后规约
优点:
- 惰性求值
计算过程
递归过程
过程定义中直接或间接地引用了过程本身,这样的过程叫做递归过程
递归计算过程
用推迟执行的运算链条描述的计算过程
迭代计算过程
用固定数目的状态变量描述的计算过程
树形递归计算过程
计算步骤数正比于树中节点数,空间需求正比于树的最大深度