什么是“向下函数”?

发布于 2024-07-14 01:06:05 字数 981 浏览 4 评论 0 原文

Jamie Zawinski 在他的 (1997) 文章“java 很糟糕” 好像你应该知道它的意思:

我真的很讨厌缺少向下的 funargs; 匿名类是一个蹩脚的替代品。 (我可以在没有长期闭包的情况下生活,但我发现缺少函数指针是一个巨大的痛苦。)

这似乎是 Lisper 的俚语,我可以找到以下简短定义 这里,但不知何故,我想我仍然不明白:

许多闭包仅在它们引用的绑定范围内使用; 这些在 Lisp 术语中被称为“向下 funargs”。

如果不是 Steve Yegge,我现在会觉得很愚蠢,但看起来,可能是可以问:

杰米·扎文斯基是一位英雄。 一个活着的传奇。 [...] 一个可以使用“向下的 funargs”这个词,然后瞪着你,只是敢于让你解释一下的家伙,你这个白痴。

-- XEmacs 已死, XEmacs万岁

那么有 Lisper 吗谁能为像我这样的 C 风格程序员编译这个?

Jamie Zawinski uses that term in his (1997) article "java sucks" as if you should know what it means:

I really hate the lack of downward-funargs; anonymous classes are a lame substitute. (I can live without long-lived closures, but I find lack of function pointers a huge pain.)

It seems to be Lisper's slang, and I could find the following brief definition here, but somehow, I think I still don't get it:

Many closures are used only during the extent of the bindings they refer to; these are known as "downward funargs" in Lisp parlance.

Were it not for Steve Yegge, I'd just feel stupid now, but it seems, it might be OK to ask:

Jamie Zawinski is a hero. A living legend. [...] A guy who can use the term "downward funargs" and then glare at you just daring you to ask him to explain it, you cretin.

-- XEmacs is dead, long live XEmacs

So is there a Lisper here who can compile this for C-style-programmers like me?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

盗梦空间 2024-07-21 01:06:05

向下 funargs 是不会返回或以其他方式离开其声明范围的本地函数。 它们只能从当前作用域向下传递给其他函数。

两个例子。 这是一个向下的函数:

function () {
    var a = 42;
    var f = function () { return a + 1; }
    foo(f); // `foo` is a function declared somewhere else.
}

虽然这不是:

function () {
    var a = 42;
    var f = function () { return a + 1; }
    return f;
}

Downward funargs are local functions that are not returned or otherwise leave their declaration scope. They only can be passed downwards to other functions from the current scope.

Two examples. This is a downward funarg:

function () {
    var a = 42;
    var f = function () { return a + 1; }
    foo(f); // `foo` is a function declared somewhere else.
}

While this is not:

function () {
    var a = 42;
    var f = function () { return a + 1; }
    return f;
}
刘备忘录 2024-07-21 01:06:05

为了更好地理解这个术语的来源,您需要了解一些历史。

老 Lisp 黑客可能会区分向下 funargs 和一般 funargs 的原因是,向下 funargs 在缺乏词汇变量的传统 Lisp 中很容易实现,而一般情况则很难。

传统上,局部变量是通过将绑定(变量的符号名称,与其值配对)添加到环境来在Lisp解释器中实现的。 使用关联列表可以简单地实现这样的环境。 每个函数都有自己的环境,以及指向父函数环境的指针。 通过在当前环境中查找来解析变量引用,如果在当前环境中找不到,则在父环境中查找,依此类推,直到到达全局环境为止。

在这样的实现中,局部变量影子具有相同名称的全局变量。 例如,在 Emacs Lisp 中,print-length 是一个全局变量,它指定在缩写之前要打印的列表的最大长度。 通过在函数调用周围绑定此变量,您可以更改该函数内 print 语句的行为:

(defun foo () (print '(1 2 3 4 5 6))) ; output depends on the value of print-length

(foo) ; use global value of print-length
  ==>  (1 2 3 4 5 6)

(let ((print-length 3)) (foo)) ; bind print-length locally around the call to foo.
  ==>  (1 2 3 ...)

您可以看到,在这样的实现中,向下 funargs 确实很容易实现,因为变量在函数创建时的环境中仍将在函数求值时的环境中。

像这样起作用的变量称为特殊动态变量,您可以使用特殊声明。

To better understand where the term comes from, you need to know some history.

The reason why an old Lisp hacker might distinguish downward funargs from funargs in general is that downward funargs are easy to implement in a traditional Lisp that lacks lexical variables, whereas the general case is hard.

Traditionally a local variable was implemented in a Lisp interpreter by adding a binding (the symbol name of the variable, paired with its value) to the environment. Such an environment was simple to implement using an association list. Each function had its own environment, and a pointer to the environment of the parent function. A variable reference was resolved by looking in the current environment, and if not found there, then in the parent environment, and so on up the stack of environments until the global environment was reached.

In such an implementation, local variables shadow global variables with the same name. For example, in Emacs Lisp, print-length is a global variable that specifies the maximum length of list to print before abbreviating it. By binding this variable around the call to a function you can change the behaviour of print statements within that function:

(defun foo () (print '(1 2 3 4 5 6))) ; output depends on the value of print-length

(foo) ; use global value of print-length
  ==>  (1 2 3 4 5 6)

(let ((print-length 3)) (foo)) ; bind print-length locally around the call to foo.
  ==>  (1 2 3 ...)

You can see that in such an implementation, downward funargs are really easy to implement, because variables that are in the environment of the function when it's created will still be in the environment of the function when it's evaluated.

Variables that act like this are called special or dynamic variables, and you can create them in Common Lisp using the special declaration.

对你再特殊 2024-07-21 01:06:05

在 Common Lisp 中:

(let ((a 3))
  (mapcar (lambda (b) (+ a b))
          (list 1 2 3 4)))

->  (4 5 6 7)

在上面的形式中,lambda 函数是向下传递的。 当被高阶函数 MAPCAR 调用时(它获取一个函数和一个值列表作为参数,然后将该函数应用于列表的每个元素并返回结果列表),lambda 函数仍然引用该变量来自 LET 表达式的“a”。 但这一切都发生在 LET 表达式内。

将上面与此版本进行比较:

(mapcar (let ((a 3))
          (lambda (b) (+ a b)))
        (list 1 2 3 4))

这里 lambda 函数是从 LET 返回的。 向上一点。 然后它被传递到 MAPCAR。 当 MAPCAR 调用 lambda 函数时,其周围的 LET 不再执行 - 该函数仍然需要引用 LET 中的变量“a”。

In Common Lisp:

(let ((a 3))
  (mapcar (lambda (b) (+ a b))
          (list 1 2 3 4)))

->  (4 5 6 7)

In above form the lambda function is passed DOWNWARD. When called by the higher-order function MAPCAR (which gets a function and a list of values as arguments, and then applies the function to each element of the list and returns a list of the results), the lambda function still refers to the variable 'a' from the LET expression. But it happens all within the LET expression.

Compare above with this version:

(mapcar (let ((a 3))
          (lambda (b) (+ a b)))
        (list 1 2 3 4))

Here the lambda function is returned from the LET. UPWARD a bit. It then gets passed to the MAPCAR. When MAPCAR calls the lambda function, its surrounding LET is no longer executing - still the function needs to reference the variable 'a' from the LET.

一紙繁鸢 2024-07-21 01:06:05

Wiki 上有一篇描述性很强的文章,名为 Funarg 问题

“向下的 funarg 也可以指
函数的状态,当该函数
并没有真正执行。 然而,
因为根据定义,存在
一个向下的 funarg 包含在
函数的执行
创建它,激活记录
该函数通常仍然可以是
存储在堆栈中。”

There's a pretty descriptive article on Wiki called Funarg problem

"A downwards funarg may also refer to
a function's state when that function
is not actually executing. However,
because, by definition, the existence
of a downwards funarg is contained in
the execution of the function that
creates it, the activation record for
the function can usually still be
stored on the stack."

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文