提交 69381b3a 编写于 作者: W wizardforcel

typo

上级 ab24cc3b
...@@ -723,7 +723,7 @@ hello world ...@@ -723,7 +723,7 @@ hello world
Logo 的用户定义过程所产生的调用过程和 Python 中的过程类似。在一系列参数上调用过程以使用新的帧扩展当前环境,以及将过程的形参绑定到实参开始,之后在开始于新帧的环境中求出过程体的代码行。 Logo 的用户定义过程所产生的调用过程和 Python 中的过程类似。在一系列参数上调用过程以使用新的帧扩展当前环境,以及将过程的形参绑定到实参开始,之后在开始于新帧的环境中求出过程体的代码行。
`output`的调用在 Logo 中与 Python 中的`return`语句有相同作用:它会中止过程体的执行,并返回一个值。Logo 过程可以通过调用`stop`而不返回任何值 `output`的调用在 Logo 中与 Python 中的`return`语句有相同作用:它会中止过程体的执行,并返回一个值。Logo 过程可以通过调用`stop`来不带任何值返回
```logo ```logo
? to count ? to count
...@@ -737,7 +737,7 @@ Logo 的用户定义过程所产生的调用过程和 Python 中的过程类似 ...@@ -737,7 +737,7 @@ Logo 的用户定义过程所产生的调用过程和 Python 中的过程类似
2 2
``` ```
**作用域。**Logo 是动态作用域的语言。类似 Python 的此法作用域语言并不允许一个函数的局部名称影响另一个函数的求值,除非第二个函数显式定义在第一个函数内。两个顶层函数的形参完全是隔离的。在动态作用域的语言中,没有这种隔离。当一个函数调用另一个函数时,绑定到第一个函数局部帧的名称可在第二个函数的函数体中访问: **作用域。**Logo 是动态作用域语言。类似 Python 的词法作用域语言并不允许一个函数的局部名称影响另一个函数的求值,除非第二个函数显式定义在第一个函数内。两个顶层函数的形参完全是隔离的。在动态作用域的语言中,没有这种隔离。当一个函数调用另一个函数时,绑定到第一个函数局部帧的名称可在第二个函数的函数体中访问:
```logo ```logo
? to print_last_x ? to print_last_x
...@@ -750,15 +750,15 @@ Logo 的用户定义过程所产生的调用过程和 Python 中的过程类似 ...@@ -750,15 +750,15 @@ Logo 的用户定义过程所产生的调用过程和 Python 中的过程类似
5 5
``` ```
虽然名称`x`并没有在全局帧中绑定,而是在`print_x`的局部帧中,也就是首先调用的函数。Logo 的动态作用域规则允许函数`print_last_x`引用`x`,它被绑定到`print_x`的形式参数上。 虽然名称`x`并没有在全局帧中绑定,而是在`print_x`的局部帧中,也就是首先调用的函数。Logo 的动态作用域规则允许函数`print_last_x`引用`x`,它被绑定到`print_x`的形式参数上。
动态作用域只需要一个对计算环境模型的简单修改就能实现。由用户函数调用创建的帧总是扩展当前环境。例如,上面`print_x`的调用引入了新的帧,它扩展自当前环境,当前环境中包含`print_x`的局部帧和全局帧。所以,在`print_last_x`的主题中查找`x`会发现局部帧中该名称绑定到`5`。与之相似,在 Python 的词法作用域下,`print_last_x`的帧值扩展自全局帧,而并不扩展自`print_x`的局部帧 动态作用域只需要一个对计算环境模型的简单修改就能实现。由用户函数调用创建的帧总是扩展自当前环境(调用处)。例如,上面的`print_x`调用引入了新的帧,它扩展自当前环境,当前环境中包含`print_x`的局部帧和全局帧。所以,在`print_last_x`的主体中查找`x`会发现局部帧中该名称绑定到`5`。与之相似,在 Python 的词法作用域下,`print_last_x`的帧只扩展自全局帧(定义处),而并不扩展自`print_x`的局部帧(调用处)
动态作用域语言拥有一些好处,它的过程可能不需要接受许多参数。例如,`print_last_x`上面的过程没有接受参数,但是它的行为仍然由封闭的作用域参数化。 动态作用域语言拥有一些好处,它的过程可能不需要接受许多参数。例如,`print_last_x`上面的过程没有接受参数,但是它的行为仍然由内层作用域参数化。
**常规编程。**我们的 Logo 之旅就到此为止了。我们还没有介绍任何高级特性,例如,对象系统、高阶过程,或者语句。学会在 Logo 中高效编程需要将语言的简单特性组合为有效的整体。 **常规编程。**我们的 Logo 之旅就到此为止了。我们还没有介绍任何高级特性,例如,对象系统、高阶过程,或者语句。学会在 Logo 中高效编程需要将语言的简单特性组合为有效的整体。
Logo 中没有条件表达式类型。过程`if`和`ifelde`使用调用表达式求值规则。`if`的第一个参数是个布尔单词,`True`或者`False`。第二个参数不是输出值,而是一个句子,包含如果第一个参数为`True`时需要求值的代码行。这个设计的重要结果是,第二个函数的内容如果不被用到就不会全部求值。 Logo 中没有条件表达式类型。过程`if`和`ifelse`使用调用表达式的求值规则。`if`的第一个参数是个布尔单词,`True`或者`False`。第二个参数不是输出值,而是一个句子,包含如果第一个参数为`True`时需要求值的代码行。这个设计的重要结果是,第二个函数的内容如果不被用到就不会全部求值。
```logo ```logo
? 1/0 ? 1/0
...@@ -773,7 +773,7 @@ div raised a ZeroDivisionError: division by zero ...@@ -773,7 +773,7 @@ div raised a ZeroDivisionError: division by zero
infinity infinity
``` ```
Logo 的条件语句不仅仅不需要特殊语法,而且它实际上可以使用`word`和`run`实现。`ifelse`的基本过程接受三个函数:不而单词、如果单词为`True`需要求值的句子,和如果单词为`False`需要求值的句子。通过适当命名形式参数,我们可以实现拥有相同行为的用户定义过程`ifelse2`。 Logo 的条件语句不仅仅不需要特殊语法,而且它实际上可以使用`word`和`run`实现。`ifelse`的基本过程接受三个函数:布尔单词、如果单词为`True`需要求值的句子,和如果单词为`False`需要求值的句子。通过适当命名形式参数,我们可以实现拥有相同行为的用户定义过程`ifelse2`。
```logo ```logo
? to ifelse2 :predicate :True :False ? to ifelse2 :predicate :True :False
...@@ -837,20 +837,20 @@ empty ...@@ -837,20 +837,20 @@ empty
## 3.6.3 结构 ## 3.6.3 结构
这一章描述了 Logo 解释器的普遍结构。虽然这一章是独立的,它也确实引用了配套项目。完成这个项目会从零制造出这一章描述的解释器的有效实现。 这一节描述了 Logo 解释器的通常结构。虽然这一章是独立的,它也确实引用了配套项目。完成这个项目会从零制造出这一章描述的解释器的有效实现。
Logo 的解释器可以共享计算器解释器的相同结构。解析器产生表达式数据结构,可由求值器来解释。求值函数检查表达式的形式,并且对于调用表达式,它在一些参数上调用函数来应用某个过程。但是,还是是一些结构上的不同以适应 Logo 的特殊语法。 Logo 的解释器可以拥有和计算器解释器相同的结构。解析器产生表达式数据结构,它们可由求值器来解释。求值函数检查表达式的形式,并且对于调用表达式,它在一些参数上调用函数来应用某个过程。但是,还是存在一些结构上的不同以适应 Logo 的特殊语法。
**行。**Logo 解析器并不读取一行代码,而是读取可能按序包含多个表达式的整行代码。它不返回表达式树,而是返回 Logo 句子。 **行。**Logo 解析器并不读取一行代码,而是读取可能按序包含多个表达式的整行代码。它不返回表达式树,而是返回 Logo 句子。
解析器实际上只做微小的语法分析。特别是,解析工作并不会将调用表达式的运算符和操作数子表达式区分为树的不同枝干。反之,调用表达式的组顺序排列,嵌套调用表达式表示为摊平的记号序列。最终,解析工作并不判断基本表达式,例如数值的类型,因为 Logo 没有丰富的类型系统。反之,每个元素都是单词或句子。 解析器实际上只做微小的语法分析。特别是,解析工作并不会将调用表达式的运算符和操作数子表达式区分为树的不同枝干。反之,调用表达式的组成部分顺序排列,嵌套调用表达式表示为摊平的记号序列。最终,解析工作并不判断基本表达式,例如数值的类型,因为 Logo 没有丰富的类型系统。反之,每个元素都是单词或句子。
```py ```py
>>> parse_line('print sum 10 difference 7 3') >>> parse_line('print sum 10 difference 7 3')
['print', 'sum', '10', 'difference', '7', '3'] ['print', 'sum', '10', 'difference', '7', '3']
``` ```
解析器做了很魏霞的分析,因为 Logo 的动态特性需要求值器解析嵌套表达式的结构。 解析器做了很微小的分析,因为 Logo 的动态特性需要求值器解析嵌套表达式的结构。
解析器并不会弄清句子的嵌套结构,句子中的句子表示为 Python 的嵌套列表。 解析器并不会弄清句子的嵌套结构,句子中的句子表示为 Python 的嵌套列表。
...@@ -862,15 +862,15 @@ Logo 的解释器可以共享计算器解释器的相同结构。解析器产生 ...@@ -862,15 +862,15 @@ Logo 的解释器可以共享计算器解释器的相同结构。解析器产生
`parse_line`的完整实现在配套项目的`logo_parser.py`中。 `parse_line`的完整实现在配套项目的`logo_parser.py`中。
**求值。**Logo 一次求值一行。求值器的一个框架实现定义在配套项目的`logo.py`中。有`parse_line`反馈的句子传给了`eval_line`函数,它求出行中的每个表达式。`eval_line`函数重复调用`logo_eval`,它求出行中的第一个完整表达式,直到这一行全部求值完毕,之后返回最后一个值。`logo_eval`函数求出单一的表达式。 **求值。**Logo 一次求值一行。求值器的一个框架实现定义在配套项目的`logo.py`中。从`parse_line`返回的句子传给了`eval_line`函数,它求出行中的每个表达式。`eval_line`函数重复调用`logo_eval`,它求出行中的下一个完整的表达式,直到这一行全部求值完毕,之后返回最后一个值。`logo_eval`函数求出单个表达式。
![](img/logo_eval.png) ![](img/logo_eval.png)
`logo_eval`函数求出不同形式的表达式,我们已经在上一节中介绍过它们了:基本、变量、定义、引用和调用表达式。Logo 中多元素表达式的形式可以由检查第一个元素来判断。表达式的每个形式都有自己的求值规则。 `logo_eval`函数求出不同形式的表达式:基本、变量、定义、引用和调用表达式,我们已经在上一节中介绍过它们了。Logo 中多元素表达式的形式可以由检查第一个元素来判断。表达式的每个形式都有自己的求值规则。
1. 基本表达式(可以解释为数值、`True`或`False`的单词)求值为自身。 1. 基本表达式(可以解释为数值、`True`或`False`的单词)求值为自身。
2. 变量在环境中查找。环境会在下一节中详细讨论。 2. 变量在环境中查找。环境会在下一节中详细讨论。
3. 定义处理为特殊情况。用户定义过程也在下一节中详细讨论 3. 定义处理为特殊情况。用户定义过程也在下一节中详细讨论
4. 引用表达式求值为引用的文本,它是个去掉前导引号的字符串。句子(表示为 Python 列表)也看做引用,它们求值为自身。 4. 引用表达式求值为引用的文本,它是个去掉前导引号的字符串。句子(表示为 Python 列表)也看做引用,它们求值为自身。
5. 调用表达式在当前环境中查找运算符名称,并且调用绑定到该名称的过程。 5. 调用表达式在当前环境中查找运算符名称,并且调用绑定到该名称的过程。
...@@ -893,7 +893,7 @@ Logo 的解释器可以共享计算器解释器的相同结构。解析器产生 ...@@ -893,7 +893,7 @@ Logo 的解释器可以共享计算器解释器的相同结构。解析器产生
return apply_procedure(procedure, line, env) return apply_procedure(procedure, line, env)
``` ```
上面的最后情况调用了第二个过程,它由函数`apply_procedure`来表达。为了调用由运算符记号命名的过程,这个运算符会在当前环境中查找。在上面的定义中,`env`是`Environment `类的实例,会在下一节中描述。`env.procedures`属性是个储存运算符名称和过程之间映射的字典。在 Logo 中,环境拥有单词的这种映射,并且没有局部定义的过程。而且,Logo 为过程名称和变量名称维护分离的映射,叫做分离的命名空间。但是,以这种方式复用名称并不推荐。 上面的最后情况调用了第二个过程,表达为函数`apply_procedure`。为了调用由运算符记号命名的过程,这个运算符会在当前环境中查找。在上面的定义中,`env`是`Environment `类的实例,会在下一节中描述。`env.procedures`属性是个储存运算符名称和过程之间映射的字典。在 Logo 中,环境拥有单词的这种映射,并且没有局部定义的过程。而且,Logo 为过程名称和变量名称维护分离的映射,叫做分离的命名空间。但是,以这种方式复用名称并不推荐。
**过程调用。**过程调用以调用`apply_procedure`函数开始,它被传入由`logo_apply`查找到的函数,并带有代码的当前行和当前环境。Logo 中过程调用的过程比计算器中的`calc_apply`更加通用。特别是,`apply_procedure`必须检查打算调用的过程,以便在求解`n`个运算符表达式之前,判断它的参数数量`n`。这里我们会看到,为什么 Logo 解析器不能仅仅由语法分析构建表达式树,因为树的结构由过程决定。 **过程调用。**过程调用以调用`apply_procedure`函数开始,它被传入由`logo_apply`查找到的函数,并带有代码的当前行和当前环境。Logo 中过程调用的过程比计算器中的`calc_apply`更加通用。特别是,`apply_procedure`必须检查打算调用的过程,以便在求解`n`个运算符表达式之前,判断它的参数数量`n`。这里我们会看到,为什么 Logo 解析器不能仅仅由语法分析构建表达式树,因为树的结构由过程决定。
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册