是否对Rebol和Red中的定义范围进行了总体解释 [英] Is there a overall explanation about definitional scoping in Rebol and Red

查看:115
本文介绍了是否对Rebol和Red中的定义范围进行了总体解释的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

REBOL/核心用户指南中,和什么是红色,我了解到Rebol和Red都使用定义范围界定.

From the REBOL/Core Users Guide, and What is Red, I have learned that both Rebol and Red use definitional scoping.

从该指南中,我知道它是静态作用域的一种形式,变量的范围是在定义其上下文时确定的",也称为

From the guide, I know it is a form of static scoping, "the scope of a variable is determined when its context is defined", and is also called runtime lexical scoping, and is a dynamic form of static scoping that depends on context definitions.

我知道在com-sci中,作用域有两种形式:词汇作用域(静态作用域)和动态作用域.这个确定性作用域使我感到困惑.

I know in com-sci, there are two forms of scoping: lexical scoping (static scoping) and dynamic scoping. This definitional scoping confused me.

那么什么是定义范围?

So what is definitional scoping?

推荐答案

Rebol实际上根本没有作用域.

让我们看一下这段代码:

Let's take this code:

rebol []

a: 1

func-1: func [] [a]

inner: context [
    a: 2
    func-2: func [] [a]
    func-3: func [/local a] [a: 3 func-1]
]

因此,加载该代码后,如果Rebol具有词法作用域,则您将看到以下内容:

So, with that code loaded, if Rebol had lexical scoping, this is what you'd see:

>> reduce [func-1 inner/func-2 inner/func-3]
== [1 2 1]

那是因为func-1使用外部作用域中的afunc-2使用的a来自内部作用域,并且func-3调用func-1,后者仍使用a不管func-3中的内容如何,​​都从定义它的外部范围开始.

That would be because func-1 uses the a from the outer scope, the a used by func-2 is from the inner scope, and func-3 calls func-1, which still uses a from the outer scope where it was defined regardless of what's in func-3.

如果Rebol具有动态范围,这就是您所看到的:

If Rebol had dynamic scoping, this is what you'd see:

>> reduce [func-1 inner/func-2 inner/func-3]
== [1 2 3]

那是因为func-3重新定义a,然后调用func-1,后者仅使用a的最新活动定义.

That would be because func-3 redefines a, then calls func-1, which just uses the most recent active definition of a.

现在,对于Rebol,您将获得第一个结果.但是Rebol没有词汇范围.那为什么呢?

Now for Rebol, you get that first result. But Rebol doesn't have lexical scoping. So why?

Rebol伪造它.这是它的工作原理.

Rebol fakes it. Here's how it works.

在编译语言中,您具有作用域.编译器遍历文件时,它会跟踪当前作用域,然后在看到嵌套作用域成为当前作用域时跟踪该作用域.对于词法作用域,编译器保留对外部作用域的引用,然后通过跟踪到外部作用域的链接来查找当前作用域中未定义的词,直到找到或找不到该词为止.动态范围的语言可以执行类似的操作,但是在运行时会增加调用堆栈.

In compiled languages, you have scopes. As the compiler goes through the file, it keeps track of the current scope, then when it sees a nested scope that becomes the current scope. For lexical scoping, the compiler keeps a reference to the outer scope, and then looks up words that weren't defined in the current scope by following the links to the outer scopes, until it finds the word, or doesn't. Dynamic-scoped languages do something similar, but at runtime, going up the call stack.

Rebol不执行任何操作;特别是它不是在运行时编译而是构建的.您认为的代码实际上是数据,单词块,数字等.单词是在其中具有称为绑定"的指针的数据结构.

Rebol doesn't do any of that; in particular it isn't compiled, it's built, at runtime. What you think of as code is actually data, blocks of words, numbers and such. The words are data structures that have a pointer in them called a "binding".

首次加载该脚本时,脚本中的所有单词都会添加到脚本的环境对象中(尽管我们没有适当地将其称为上下文").收集单词时,脚本数据会更改.在脚本的上下文"中找到的任何单词都链接到上下文"或绑定".这些绑定意味着您只需跟随该链接即可到达存储该单词值的对象.真的很快.

When that script is first loaded all the words in the script are added to the environment object of the script (which we inappropriately call a "context", though it's not). While the words are being gathered, the script data is changed. Any word found in the script's "context" is linked to the "context", or "bound". Those bindings mean that you can just follow that one link and get to the object where the value of that word is stored. It's really fast.

然后,一旦完成,我们就开始运行脚本.然后,我们进行以下操作:func [] [a].那实际上不是声明,而是对名为func的函数的调用,该函数接受一个spec块和一个代码块,并使用它们来构建函数.该函数还获得了自己的环境对象,但是在函数的规范中声明了单词.在这种情况下,规范中没有文字,因此它是一个空对象.然后将代码块绑定到该对象.但是在这种情况下,该对象中没有a,因此对a不做任何操作,它会保留从绑定之前到绑定之前的绑定.

Then, once that's done, we start running the script. And then we get to this bit: func [] [a]. That is not really a declaration, that's a call to a function named func which takes a spec block and a code block and uses them to build a function. That function also gets its own environment object, but with words declared in the function's spec. In this case there are no words in the spec, so it's an empty object. Then the code block is bound to that object. But in this case there is no a in that object, so nothing is done to the a, it keeps the binding it already had from when it was bound before.

context [...]调用也是如此-是的,这是对不恰当地命名为context的函数的调用,该函数通过调用make object!来构建对象. context函数获取一个数据块,然后搜索设置词(带有冒号的那些东西,例如a:),然后在其中构建带有这些词的对象,然后将其中的所有词绑定该块以及所有嵌套块到对象中的单词(在本例中为afunc-2func-3).这意味着该代码块中的a的绑定已更改 ,以指向该对象.

Same goes for the context [...] call - yes, that's a call to a function inappropriately named context, which builds an object by calling make object!. The context function takes a block of data, and it searches for set-words (those things with the trailing colons, like a:), then builds an object with those words in it, then it binds all of the words in that block and all the nested blocks to the words that are in the object, in this case a, func-2 and func-3. And that means that the a's in that block of code have their bindings changed, to point to that object instead.

定义func-2时,a在其代码块中的绑定不会被覆盖.定义func-3时,其规格中具有a,因此a:的绑定被覆盖.

When func-2 is defined, the binding of the a in its code block is not overridden. When func-3 is defined, it has an a in its spec, so the a: has its binding overridden.

所有这些有趣的事情是根本没有任何作用域. func-1的代码主体中的第一个a:a仅绑定一次,因此它们保持第一个绑定. inner的代码块中的a:func-2a被绑定两次,因此它们保持第二个绑定. func-3代码中的a:被绑定三次,因此它也保留了最后的绑定.它不是作用域,只是绑定了代码,然后再次绑定了较小的代码,依此类推,直到完成为止.

The funny thing about all of this is that there aren't any scopes at all. That first a: and the a in func-1's code body are only bound once, so they keep their first binding. The a: in inner's code block and the a in func-2's are bound twice, so they keep their second binding. The a: in func-3's code is bound three times, so it also keeps its last binding. It's not scopes, it's just code being bound and then smaller bits of code being bound again, and so on until it's done.

每轮绑定由定义"某些东西的函数执行(实际上是在构建它),然后当该代码运行并调用定义其他东西的其他函数时,这些函数对其下一个对象执行另一轮绑定代码的子集.这就是为什么我们称其为定义范围";虽然它实际上不是作用域,但它是Rebol中作用域的目的,它与词汇作用域的行为足够接近,乍看之下您无法分辨出差异.

Each round of binding is performed by a function that is "defining" something (really, building it), and then when that code runs and calls other functions that define something else, those functions perform another round of binding to its little subset of code. That's why we call it "definitional scoping"; while it really isn't scoping, it is what serves the purpose of scoping in Rebol, and it's close enough to the behavior of lexical scoping that on first glance you can't tell the difference.

当您意识到这些绑定是直接的并且可以更改它们(实际上,您可以用相同的名称和不同的绑定来制作新单词)时,它的确会变得不同.这些定义函数所调用的函数相同,您可以自称:它名为bind.使用bind,您可以打破范围界定的幻想,并使单词绑定到您可以访问的任何对象.您可以使用bind做奇妙的技巧,甚至可以自己定义功能.充满乐趣!

It really becomes different when you realize that these bindings are direct, and you can change them (sort of, you can make new words with the same name and a different binding). That same function that those definition functions call, you can call yourself: it's named bind. With bind you can break the illusion of scoping and make words that bind to any object you can get access to. You can do wonderful tricks with bind, even make your own definition functions. It's loads of fun!

对于Red来说,Red是可编译的,但它还包括类似Rebol的解释器,绑定和所有好东西.当使用解释器定义事物时,它也会进行定义作用域.

As for Red, Red is compilable, but it also includes a Rebol-like interpreter, binding and all of the goodies. When it's defining things with the interpreter it does definitional scoping as well.

这有助于使事情更清楚吗?

Does that help make things more clear?

这篇关于是否对Rebol和Red中的定义范围进行了总体解释的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆