【问题标题】:How does the definition for `apply-partially` work in Emacs 24?`apply-partially` 的定义如何在 Emacs 24 中工作?
【发布时间】:2011-10-27 08:09:08
【问题描述】:

apply-partially 的 Emacs 代码是这样的:

(defun apply-partially (fun &rest args)
  "Return a function that is a partial application of FUN to ARGS.
ARGS is a list of the first N arguments to pass to FUN.
The result is a new function which does the same as FUN, except that
the first N arguments are fixed at the values with which this function
was called."
  `(closure (t) (&rest args)
            (apply ',fun ,@(mapcar (lambda (arg) `',arg) args) args)))

它返回一个看起来很像 lambda 表达式的列表,除了 lambdaclosure (t) 替换。例如,(apply-partially 'cons 1) 返回:

(closure (t) (&rest args) (apply (quote cons) (quote 1) args))

据我所知,它的外观和工作方式完全一样:

(lambda (&rest args) (apply (quote cons) (quote 1) args))

除了“闭包”表达式没有 lambda 的“自引用”属性,所以当我尝试评估它时,Emacs 告诉我closure 没有函数定义:Lisp error: (void-function closure)

我在 Elisp 手册中找不到以这种方式使用符号 closure 的任何参考。这似乎是某种 Emacs 内部的魔法。显然没有根据正常规则评估闭包表达式(因为手动执行此操作会出错)。

那么这里发生了什么?我是否需要对 C 代码中的“闭包”引用进行 grep 查找?

编辑:似乎在 Emacs 23 及更低版本中,apply-partially 只是使用 cl 包中的 lexical-let 来进行闭包。以上定义来自“24.0.90.1”版本。

【问题讨论】:

    标签: emacs closures elisp


    【解决方案1】:

    我在eval.cfuncall_lambda 函数中找到了答案:

      if (EQ (XCAR (fun), Qclosure))
    {
      fun = XCDR (fun); /* Drop `closure'.  */
      lexenv = XCAR (fun);
      CHECK_LIST_CONS (fun, fun);
    }
      else
    lexenv = Qnil;
    

    closure (t) 似乎是 lambda 的词法等价物。第二个元素(t) 被分配给lexenv,所以我猜这个元素是为了关闭在函数本身或其他东西之外定义的词法值。

    我怀疑缺少自引用可能是疏忽,可以通过以下方式进行补救:

    (defmacro make-self-quoting (name)
      "Make NAME into a self-quoting function like `lambda'."
      `(defmacro ,name (&rest cdr)
         (list 'function (cons ',name cdr))))
    (make-self-quoting closure)
    

    【讨论】:

    • 对,在 apply-partially 的情况下,词法环境是空的,但仍然有一个区别:args 参数将是词法绑定的,而 lambda 将是动态绑定。这可确保名称 args 不会干扰该变量在其他地方的其他用途。
    • 至于没有自引用,这并不是真正的疏忽,根本不需要:(closure ...) 不应该出现在源代码中。
    【解决方案2】:

    在我的“GNU Emacs 23.2.1 (i686-pc-cygwin)”中,它被定义为

    (defun apply-partially (fun &rest args)
      "Return a function that is a partial application of FUN to ARGS.              
    ARGS is a list of the first N arguments to pass to FUN.                         
    The result is a new function which does the same as FUN, except that            
    the first N arguments are fixed at the values with which this function          
    was called."
      (lexical-let ((fun fun) (args1 args))
        (lambda (&rest args2) (apply fun (append args1 args2)))))
    

    在这里理解它的工作原理似乎很容易:lambda 记住部分参数集,并在调用原始函数时附加其余部分。

    【讨论】:

    • 我正在运行 Emacs 24,它现在有自己的词法范围,不依赖于 cl 包。我猜closure 对 Emacs 24 来说是新的。
    • 如果 closure 是一个符号,那么 apropos 一定有一些关于它的东西?
    • emacswiki.org/emacs/closure2.el 有一个 defmacro closure 但不清楚它是否是 Emacs 的一部分。
    • 不,文档中的任何地方都没有提到“闭包”符号。它从不直接在任何 elisp 代码中使用,仅在 C 代码中使用,因此在某种意义上它是 Emacs 内部结构的一部分。
    猜你喜欢
    • 2013-03-22
    • 2022-01-14
    • 1970-01-01
    • 2020-04-12
    • 1970-01-01
    • 2016-08-19
    • 2020-09-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多