62

Jamie Zawinski在他的 (1997)文章“java 糟透了”中使用了这个术语,好像你应该知道它的意思:

我真的很讨厌缺乏向下的燃料;匿名类是一个蹩脚的替代品。(我可以不用长寿命的闭包,但我发现缺少函数指针是一个巨大的痛苦。)

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

许多闭包仅在它们所指的绑定范围内使用;在 Lisp 用语中,这些被称为“downward funargs”。

如果不是因为Steve Yegge,我现在会觉得很愚蠢,但看起来,问一下可能没问题:

杰米·扎温斯基是个英雄。一个活生生的传奇。[...]一个可以使用“downward funargs”这个词然后瞪着你的家伙,只是胆敢让他解释它,你这个白痴。

-- XEmacs 已死,XEmacs 万岁

那么这里有没有一个 Lisper 可以为像我这样的 C 风格程序员编译这个?

4

4 回答 4

58

向下的函数参数是不返回或以其他方式离开其声明范围的局部函数。它们只能从当前范围向下传递给其他函数。

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

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;
}
于 2009-02-24T10:12:35.700 回答
30

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

一个老 Lisp 黑客可能会从一般的函数参数中区分出向下函数参数的原因是,向下函数参数在缺乏词法变量的传统 Lisp 中很容易实现,而一般情况下很难实现。

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

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

(defun foo () (print '(1 2 3 4 5 6))) ; 输出取决于 print-length 的值

(foo) ; 使用 print-length 的全局值
  ==> (1 2 3 4 5 6)

(let ((print-length 3)) (foo)) ; 在对 foo 的调用周围本地绑定 print-length。
  ==> (1 2 3 ...)

您可以看到,在这样的实现中,向下的函数参数非常容易实现,因为在函数创建时处于函数环境中的变量在计算时仍将在函数环境中。

这种行为的变量称为特殊变量或动态变量,您可以使用special声明在 Common Lisp 中创建它们。

于 2009-02-25T20:18:48.027 回答
16

在 Common Lisp 中:

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

->  (4 5 6 7)

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

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

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

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

于 2009-02-24T15:45:02.513 回答
12

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

“向下函数参数也可以指函数未实际执行时的状态。但是,根据定义,向下函数参数的存在包含在创建它的函数的执行中,函数的激活记录通常仍然可以存储在堆栈中。”

于 2009-02-24T10:11:36.247 回答