vav*_*ava 26 emacs closures elisp
我正在尝试创建一个将返回一个常量值的函数.
在JavaScript和其他现代命令式语言中,我会使用闭包:
function id(a) {
return function() {return a;};
}
Run Code Online (Sandbox Code Playgroud)
但是Emacs lisp并不支持这些.
我可以创建身份功能和部分功能应用程序的混合,但它也不支持.
那我该怎么做?
vav*_*ava 29
找到lexical-let的另一个解决方案
(defun foo (n)
(lexical-let ((n n)) #'(lambda() n)))
(funcall (foo 10)) ;; => 10
Run Code Online (Sandbox Code Playgroud)
Ber*_*ley 14
Emacs中的真实(非假)闭包24.
虽然当变量词法绑定具有值t时,Emacs 24具有词法挖掘,但是在词汇绑定上下文中,defun特殊形式不能正常工作(至少在Emacs 24.2.1中没有.)这使得很难但并非不可能定义真实(非假)闭包.例如:
(let ((counter 0))
(defun counting ()
(setq counter (1+ counter))))
Run Code Online (Sandbox Code Playgroud)
按预期的符号将无法正常工作计数器在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))))))
Run Code Online (Sandbox Code Playgroud)
如果您按如下方式定义计数:
(let ((counter 0))
(defun** counting ()
(setq counter (1+ counter))))
Run Code Online (Sandbox Code Playgroud)
它将按预期工作,并在每次调用时更新词法绑定变量计数,同时返回新值.
CAVEAT:如果你尝试defun**与一个词法绑定变量同名的函数,宏将无法正常工作.即如果您执行以下操作:
(let ((dont-do-this 10))
(defun** dont-do-this ()
.........
.........))
Run Code Online (Sandbox Code Playgroud)
我无法想象有人会这样做,但值得一提.
注:我有一个名为宏defun定义** ,使其不与宏交锋defun定义*在CL包,但是它不依赖于对包的任何方式.
愚蠢的想法:怎么样:
(defun foo (x)
`(lambda () ,x))
(funcall (foo 10)) ;; => 10
Run Code Online (Sandbox Code Playgroud)
Emacs lisp只有动态范围.有一个lexical-let宏通过一个相当可怕的黑客来近似词汇范围.
我对Emacs Lisp并不坚定,但就我所知,与Common Lisp的一个重大区别在于它始终使用动态范围.该的Emacs Lisp手册指出的Emacs Lisp没有关闭.
我将尝试运用我对动态范围的理论知识.
如果你有一个id只返回值的函数my-id:
(defun id () my-id)
你在其他一些功能中使用它:
(defun some-other-place () (id))
在id你my-id通过例如let 绑定的方式的某个地方:
(defun even-elsewhere ()
(let ((my-id 5))
(some-other-place)))
这应该回馈5.
我知道当你习惯词法范围时,动态范围是一种奇怪的野兽,但也许你可以用它来实现你想要的行为.
| 归档时间: |
|
| 查看次数: |
5587 次 |
| 最近记录: |