我正在尝试创建一个将返回一个常量值的函数.
在JavaScript和其他现代命令式语言中,我会使用闭包:
function id(a) { return function() {return a;}; }
但是Emacs lisp并不支持这些.
我可以创建身份功能和部分功能应用程序的混合,但它也不支持.
那我该怎么做?
找到lexical-let的另一个解决方案
(defun foo (n) (lexical-let ((n n)) #'(lambda() n))) (funcall (foo 10)) ;; => 10
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包,但是它不依赖于对包的任何方式.
愚蠢的想法:怎么样:
(defun foo (x) `(lambda () ,x)) (funcall (foo 10)) ;; => 10
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.
我知道当你习惯词法范围时,动态范围是一种奇怪的野兽,但也许你可以用它来实现你想要的行为.