代码之家  ›  专栏  ›  技术社区  ›  vava

如何在Emacs Lisp中执行闭包?

  •  32
  • vava  · 技术社区  · 17 年前

    在JavaScript和其他现代命令式语言中,我会使用闭包:

    function id(a) {
        return function() {return a;};
    }
    

    我可以创建身份函数和部分函数应用程序的组合,但也不支持。

    7 回复  |  直到 14 年前
        1
  •  35
  •   vava    17 年前

    使用词法let找到了另一种解决方案

    (defun foo (n) 
        (lexical-let ((n n)) #'(lambda() n)))
    
    (funcall (foo 10)) ;; => 10
    
        2
  •  13
  •   Bernard Hurley    13 年前

    Emacs 24中的真实(非虚假)闭包。

    词汇绑定 有价值 特殊形式在受词汇约束的上下文中不能正常工作(至少在Emacs 24.2.1中不能。)这使得它很难,但 不可能定义真实(而非虚假)的闭包。例如:

    (let ((counter 0))
       (defun counting ()
        (setq counter (1+ counter))))
    

    计数器 函数定义 计数 如果全局变量不存在,那么它显然会失败。然而,如果有这样一个全局变量,它就会被更新,这可能不是预期的,而且可能是一个难以追踪的错误,因为函数可能看起来工作正常。

    函数定义

    (defmacro defun** (name args &rest body)
      "Define NAME as a function in a lexically bound context.
    
    Like normal `defun', except that it works correctly in lexically
    bound contexts.
    
    \(fn NAME ARGLIST [DOCSTRING] BODY...)"
      (let ((bound-as-var (boundp  `,name)))
        (when (fboundp `,name)
          (message "Redefining function/macro: %s" `,name))
        (append
         `(progn
            (defvar ,name nil)
            (fset (quote ,name) (lambda (,@args) ,@body)))
         (if bound-as-var
             'nil
             `((makunbound `,name))))))
    

    如果你定义 计数

    (let ((counter 0))
      (defun** counting ()
        (setq counter (1+ counter))))
    

    它将按预期工作,并更新受词法约束的变量 每次调用它时,都会返回新值。

    警告: defun** 与词汇绑定变量之一同名的函数。即,如果你做以下事情:

    (let ((dont-do-this 10))
      (defun** dont-do-this ()
        .........
        .........))
    

    我无法想象有人真的这样做,但值得一提。

    注意:我已经命名了宏 defun** 函数定义 然而,它并不以任何方式依赖于那个包。

        3
  •  10
  •   Ken    17 年前

    (defun foo (x)
      `(lambda () ,x))
    
    (funcall (foo 10))  ;; => 10
    
        4
  •  7
  •   Allen    17 年前

    lexical-let 通过相当糟糕的破解来近似词汇范围的宏。

        5
  •  4
  •   Steve Yu    13 年前

    Emacs 24具有词法绑定功能。

    http://www.emacswiki.org/emacs/LexicalBinding

        6
  •  3
  •   Stefan    7 年前
    ;; -*- lexical-binding:t -*-
    
    (defun create-counter ()
      (let ((c 0))
        (lambda ()
          (setq c (+ c 1))
          c)))
    
    (setq counter (create-counter))
    
    (funcall counter) ; => 1
    (funcall counter) ; => 2
    (funcall counter) ; => 3 ...