当前位置:  开发笔记 > 编程语言 > 正文

如何在Emacs Lisp中关闭?

如何解决《如何在EmacsLisp中关闭?》经验,为你挑选了5个好方法。

我正在尝试创建一个将返回一个常量值的函数.

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

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

但是Emacs lisp并不支持这些.

我可以创建身份功能和部分功能应用程序的混合,但它也不支持.

那我该怎么做?



1> vava..:

找到lexical-let的另一个解决方案

(defun foo (n) 
    (lexical-let ((n n)) #'(lambda() n)))

(funcall (foo 10)) ;; => 10



2> Bernard Hurl..:

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

虽然当变量词法绑定具有值t时,Emacs 24具有词法挖掘,但是在词汇绑定上下文中,defun特殊形式不能正常工作(至少在Emacs 24.2.1中没有.)这使得很难但并非不可能定义真实(非假)闭包.例如:

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

按预期的符号将无法正常工作计数器defun定义将被绑定到该名称的全局变量,如果有一个,而不是词法变量的定义让利.当调用函数计数时,如果全局变量不存在,那么它肯定会失败.但是,如果有这样一个全局变量,它会被更新,这可能不是预期的,并且可能很难追踪bug,因为该函数可能看起来工作正常.

如果您以这种方式使用defun,字节编译器会发出警告,并且可能会在以后的某个版本的Emacs中解决该问题,但在此之前可以使用以下宏:

(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))))

它将按预期工作,并在每次调用时更新词法绑定变量计数,同时返回新值.

CAVEAT:如果你尝试defun**与一个词法绑定变量同名的函数,宏将无法正常工作.即如果您执行以下操作:

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

我无法想象有人会这样做,但值得一提.

注:我有一个名为宏defun定义** ,使其不与宏交锋defun定义*CL包,但是它不依赖于对包的任何方式.


在Emacs-24.3中解除了使用`defun'定义闭包的限制(其中`defun'现在被定义为宏而不是特殊形式)。因此,由于24.3`defun`的工作方式类似于您的`defun **`宏(因此不存在损坏的`(defvar,name nil)`并修复了其他一些较小的缺点,例如使用`fset`而不是`defalias`和处理所谓的“动态文档字符串”,需要在bytecompiler中进行更改)。

3> Ken..:

愚蠢的想法:怎么样:

(defun foo (x)
  `(lambda () ,x))

(funcall (foo 10))  ;; => 10



4> Allen..:

Emacs lisp只有动态范围.有一个lexical-let宏通过一个相当可怕的黑客来近似词汇范围.


当然,"相当糟糕的黑客"是在其他语言实现的掩护下发生的事情.

5> Svante..:

我对Emacs Lisp并不坚定,但就我所知,与Common Lisp的一个重大区别在于它始终使用动态范围.该的Emacs Lisp手册指出的Emacs Lisp没有关闭.

我将尝试运用我对动态范围的理论知识.

如果你有一个id只返回值的函数my-id:

(defun id ()
  my-id)

你在其他一些功能中使用它:

(defun some-other-place ()
  (id))

idmy-id通过例如let 绑定的方式的某个地方:

(defun even-elsewhere ()
  (let ((my-id 5))
    (some-other-place)))

这应该回馈5.

我知道当你习惯词法范围时,动态范围是一种奇怪的野兽,但也许你可以用它来实现你想要的行为.

推荐阅读
刘美娥94662
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有