三个问题环境评价模型

2023-11-30

I am reading the SICP book Here about the imperative programming model. I could not understand the illustration in two points: enter image description here

  1. W.r.t.箭头从square到“对”(两个圆圈):这个箭头是什么意思?尽管在本节中,箭头表示“封闭环境”,但该特定箭头似乎并未指向环境。(square的环境是global env,而不是“对”)
  2. 下面是一个正确的理解:在一个过程定义的值中,它的“代码文本”部分(左边的圆圈)没有内部符号的解释。它们只是“文本”。仅在办理手续时应用,它们在应用程序的上下文/环境中获得意义。
  3. 如果2是正确的,为什么箭头从environment part这对中的(右边的 圈)到封闭环境是必要的吗? (因为在过程定义内的过程代码中没有解释符号含义的意义。)

SICP 的箭头表示法有点过载。我将引用文本的相关部分来理解该图。

过程对象是一对,其代码指定过程有一个形式参数,即 x 和过程体 (* x x)。该过程的环境部分是指向全局环境的指针,因为这是计算 lambda 表达式以生成该过程的环境。将过程对象与符号方块关联起来的新绑定已添加到全局框架中。一般来说,define 通过向框架添加绑定来创建定义。

那么,让我们分析一下每个箭头。

  1. “全局环境”→ 正方形。这个箭头看起来只是labeling广场作为地球环境的象征。值得注意的是,此环境是自此以来唯一存活的堆栈帧define在全局环境中被称为。

  2. “正方形”→ 两个点。这个箭头似乎表明这两个点代表的是stored在名字上"square"这是在全球环境中发现的。

  3. 左点→“参数”/“主体”。该箭头表示左边的点是一个“对象”,被认为存储着两个数据:“形式参数列表”和“过程主体”。

  4. 右点 → 正方形。这个箭头表明右边的点包含一个返回全局环境的“指针”。


这张图给出了关于 Lisp 中符号如何派生含义的高度可操作的观点。特别是,符号在特定的“上下文”中被“评估”。上下文是“环境框架”的链接列表,每个环境框架都包含一些名称→值映射的集合。为了评估符号,需要遵循该链接列表并返回从符号名称映射的第一个值。直观地看,一个例子是

"foo" → { "bar" : 3    →  { "foo" : 8 }   →   { "foo" : 10 }
        , "baz" : 4 }

在哪里评估foo回报8通过“跳过”第一帧并找到值8在第二帧中ignoring第三帧。这种忽略功能很重要——它表明某些上下文可能具有隐藏来自更大上下文的值的名称。


所以这里的整个图片表明以下内容:

  1. Calling define在全局上下文中添加一个新的名称→值映射到全局框架。
  2. 存储 lambda 对象存储两条信息(两个点)

    • 左边的点包含 lambda 正文的文本以及被视为“形式参数”的符号列表。

    • 右边的点包含对一些堆栈框架这可能是也可能不是全局框架,尽管它恰好是这张图中的全局框架

最后,我们应该谈谈计算 lambda 的含义。要计算 lambda,您必须向其传递一个列表values。它使用该输入值列表并将它们与它存储的形式参数列表进行匹配,以便生成一个新的环境框架它将形式参数映射到输入值。然后,它使用该新框架作为主框架和linked框架作为后续上下文。用图表来说,我们可以说square看起来像

        +--- Formal parameter list
       /   +--- Body of function
       |   |
(left: (x) (* x x))    (right: {global frame})

然后当我们评估它时(square 3)我们使用创建一个新框架3和形式参数列表

{ "x" : 3 }

并评估身体。首先我们查一下名字*。由于它不在我们新的本地框架中,我们必须在全局框架中找到它。

"*"   →   { "x" : 3 }   →   { global frame }

事实证明它存在,并且是乘法的定义。因此,我们需要向它传递一些值,以便我们查找“x”

"x"   →   { "x" : 3 }   →   { global frame }

since x is存储在本地框架中,我们在那里找到它并通过3 and 3作为我们找到的乘法函数的参数。

重要的部分是局部框架shadows全球框架。这意味着如果x在全球框架中也有意义,我们会override它在评估身体的背景下square.


最后,当我被要求在有关“变量”含义的问题的背景下回答这个问题时,需要注意的是,以上是一个非常特殊的问题执行变量的非常特殊的语义。从表面上看,你总是可以说“lisp 中的变量恰好意味着这个过程的发生”。不过,这可能有点具有挑战性。

“变量”一词的另一种语义(我和许多数学爱好者都喜欢)是上下文中的变量代表域中特定的、固定的但未知的值。如果我们检查lambda在体内square

(lambda (x) (* x x))

我们看到这或多或少是这个短语的预期语义——在解释时(* x x) we see x作为某种价值(例如数字),但我们对此一无所知。在口译中(lambda (x) (* x x))我们看到,为了理解 lambda 内部短语的含义,我们必须为其提供以下含义:x。这大致是到处使用的变量和函数的标准语义。

挑战在于这里描述的堆栈帧实现也可以轻松设置violate这种语义——事实上,在这个例子中它的作用非常巧妙。具体来说:define破坏语义。原因在下面的代码片段中很明显

(define foo 3)
foo
(define foo 4)
foo

在此片段中,我们按顺序评估每个短语,并看到变量的(据称“固定但未知”)值foo从第 2 行更改为第 4 行。这是因为define让我们能够edit堆栈帧位于上下文中,而不是仅仅创建一个新的上下文来遮蔽旧的上下文,例如lambda做。这意味着我们必须将变量视为不是“固定但未知”,而是一系列可变槽,不能保证随着时间的推移保持其值——这是一种更复杂的语义,也许应该迫使我们调用foo“插槽”或​​“可分配”。

我们也可以将其视为有漏洞的抽象。我们希望变量具有标准的“固定但未知”语义,但由于堆栈帧的机制和define我们并不完全遵循这个含义。

最后一点,Lisps 经常给你一个叫做let它可用于复制前面的示例,而不会丢弃变量语义:

(let ((foo 3))
  foo
  (let ((foo 4))
    foo)
  foo)

在这种情况下,foo第 2 行取值3, the foo4号线存在于不同的变量上下文中因此只有shadows the foo在第 2 行...因此采用不同的固定值4,最后foo第 5 行再次与foo在第 2 行并取相同的值。

换句话说,let允许我们创建任意本地上下文(巧合的是,正如您所期望的那样,通过在幕后创建新的堆栈帧)。不幸的是,让我们知道这些语义是安全的黄金法则被称为 α 转换。该规则规定,如果您重命名变量到处 and 均匀地在单一上下文中,程序的含义不会改变。

因此,通过 α 转换,前面的例子与这个例子的含义相同

(let ((foo 3))
  foo
  (let ((bar 4))
    bar)
  foo)

也许稍微不那么混乱,因为我们不再需要担心阴影的影响foo.


那么我们可以制作 Lisp 的吗define语义更安全?有点儿。您可能会想象以下转变:

  1. 禁止定义集中的循环依赖,例如(define x y) (define y x)不允许同时(define x 3) (define y x) isn't.
  2. 全部移动define直到任何给定上下文(堆栈帧)的最开头,并将它们按依赖顺序放置。
  3. 将“重新”设置为错误define“任何变量

事实证明,这种转换有点棘手(代码移动很困难,因此可能会出现循环依赖),但如果您解决了一些小问题,您会发现在任何上下文中,变量只能接受一个固定但未知的值价值。

您还可以找到以下内容——具有以下转换形式的任何程序

(define x ... definition of x ...)
(define y ... definition of y ...)
(define z ... definition of z ...)
... body ...

相当于下面的

(let ((x ... definition of x ...))
  (let ((y ... definition of y ...))
    (let ((z ... definition of z ...))
      ... body ...)))

这是表明我们美好、简单的“变量是固定但未知数量”语义的另一种方式。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

三个问题环境评价模型 的相关文章

  • Java中变量的默认值

    Java 中的每个类型在声明时都有一个原始值 文章原始数据类型 http docs oracle com javase tutorial java nutsandbolts datatypes html包含原始数据类型的描述 知道了这一点
  • bash后台进程修改全局变量

    在我的 Bash 脚本中 我有一个全局变量foo设置为某个值和函数过程back func这是在后台运行的 我希望后台进程能够访问foo并修改其值 以便主进程可以看到变化 我的脚本的结构如下 bin bash foo 0 function b
  • 我可以向函数添加属性以防止重入吗?

    目前 我有一些如下所示的功能 private bool inFunction1 false public void function1 if inFunction1 return inFunction1 true do stuff whic
  • 类型错误:在自定义 python 函数中找到预期字节、str

    我正在使用一种名为 Giggle 的新生物信息学工具 并且我已经在我的系统上安装了 python 包装器 尽管场景非常具体 但我认为问题非常普遍 这个功能 index Giggle create index HMEC hg19 BroadH
  • 小型简单结构是否应该通过 const 引用传递?

    我一直被教导非原始类型应该通过 const 引用传递 而不是尽可能通过值传递 即 void foo std string str bad void foo const std string str good 但我今天在想 也许实际上一些简单
  • Javascript 函数接受 PHP 变量

    我完全空白 为什么这不起作用 我可以通过一个变量来完成此操作 但不能通过两个变量 当我实际使用像这样的数字时getnt 1 2 有用 它只是不适用于两个 PHP 变量 我可以使代码与echo a href nt php nid n a
  • 是否可以替换 php 中的函数(例如邮件)并使其执行其他操作?

    我想用 PHP 重写一个函数 比如说 mail 函数 并且希望从现在开始调用 mail 时 它将加载我的 mail 版本而不是默认的 php 版本 这在 php 中可能吗 我想这样做的原因是因为我有数千行调用 mail 的代码 并且我不想重
  • 如何根据R中的条件创建新变量

    我正在尝试根据某些条件创建一个新变量 我的数据看起来像 a b 1 NA 2 3 3 3 NA 2 NA NA 我想要的是一个变量c这样 when a is not NA b is NA c a when a is NA b is not
  • 如何在类中使用常量类变量声明常量数组?

    如何在类中使用常量类变量声明常量数组 是否可以 我不想要动态数组 我的意思是这样的 class test const int size int array size public test size 50 int main test t 5
  • 如何从视图中使用模型函数? - 拉拉维尔 5.4

    我在模型类中创建了一个函数 它是 public function scopetest query return query gt pluck name 我的控制器代码是 public function index books Book al
  • 就地改变 numpy 函数输出数组

    我正在尝试编写一个对数组执行数学运算并返回结果的函数 一个简化的例子可以是 def original func A return A 1 A 1 为了加速并避免为每个函数调用分配新的输出数组 我希望将输出数组作为参数 并就地更改它 def
  • Clojure 中的宏和函数

    我在这个 Clojure 教程中读到了以下行 http java ociweb com mark clojure article html Macros http java ociweb com mark clojure article h
  • Excel VBA 中.Delete 和.Clear 的区别?

    有什么区别Worksheets 1 Cells Delete and Worksheets 1 Cells Clear 我问这个是因为我一直用 Clear清除我的工作表内容 但在我之前的帖子中我发现Worksheets 1 Cells De
  • javascript - setTimeout() 与 setInterval()

    之间的主要和次要区别是什么setTimeout and setInterval 我在网上搜索了一下 但它让我很困惑 它们之间有什么区别 主要区别是 setInterval fires again and again in intervals
  • MySQL - CONCAT - 有什么方法可以连接字符串并将其用作变量吗?

    mysql 上的时间很少 但开始探索边缘 Stackoverflow 是一个很棒的资源 谢谢大家 在尝试 Concat 时我遇到了这个问题 我知道会有办法 但我就是想不出来 我的例子 set strokes hole 10 6 set x
  • 获取ERLANG中的最长公共子序列

    我是这个 ERLANG 的新手 我了解基础知识 这就像计划 但范围更广 我知道如何创建一个函数 但在创建一个获取最长公共子序列的函数时遇到问题 lcs str1 str2 是一个接受两个字符串并输出一个整数的函数 lcs algorithm
  • 嵌套辅助函数和性能

    嵌套辅助函数对于使代码更易于理解非常有用 谷歌甚至建议在他们的应用程序中使用嵌套函数时尚指南 https google styleguide googlecode com svn trunk javascriptguide xml Nest
  • 如何在C中实现带连分数的自然对数?

    这里我有一个小问题 根据这个公式创建一些东西 这就是我所拥有的 但它不起作用 弗兰基 我真的不明白它应该如何工作 我尝试用一 些错误的指令对其进行编码 N 是迭代次数和分数部分 我认为它会以某种方式导致递归 但不知道如何 谢谢你的帮助 do
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l
  • CodeIgniter:My_Lang 中的 get_instance

    我发现这个有用的国际化代码 http pastebin com SyKmPYTX http pastebin com SyKmPYTX 一切正常 除了我无法在此类中使用 CI 函数 我想从 DB 设置 languages 和 special

随机推荐