Lisp 在另一个函数中调用flet定义的函数

Lisp 在另一个函数中调用flet定义的函数,lisp,elisp,Lisp,Elisp,我有一个在foo中定义的函数集合,我也想在bar中使用这些函数。我在foo中定义了这些函数,因为我希望foo是自包含的——否则我知道我可以在外部(全局)定义这些函数,以便foo和bar以及其他函数可以访问,或者在标签结构中定义foo和bar,其中这些函数仅为foo和bar定义。在任何情况下,我都希望foo能够在没有外部函数或标签结构的情况下进行分发。这就是挑战 这就是我到目前为止所拥有的(在本例中我使用的是Emacs Lisp),但我现在拥有的是在调用bar时全局定义foo中的本地函数。有没有关

我有一个在
foo
中定义的函数集合,我也想在
bar
中使用这些函数。我在
foo
中定义了这些函数,因为我希望
foo
是自包含的——否则我知道我可以在外部(全局)定义这些函数,以便
foo
bar
以及其他函数可以访问,或者在
标签
结构中定义
foo
bar
,其中这些函数仅为
foo
bar
定义。在任何情况下,我都希望
foo
能够在没有外部函数或
标签
结构的情况下进行分发。这就是挑战

这就是我到目前为止所拥有的(在本例中我使用的是Emacs Lisp),但我现在拥有的是在调用
bar
时全局定义
foo
中的本地函数。有没有关于如何在
栏中定义局部变量/函数的建议


这不是自足的,所以它不是一个真正的答案;但是它与您提到的其他选项不同,所以我还是要添加它

(defmacro with-foo-functions (&rest forms)
  `(flet ((addone (x) (1+ x))
          (addtwo (x) (+ 2 x)))
     ,@forms))

(defun foo (x)
  (with-foo-functions
   (addtwo x)))

(defun bar (x)
  (with-foo-functions
   (addone x)))

这不是自足的,所以它不是一个真正的答案;但是它与您提到的其他选项不同,所以我还是要添加它

(defmacro with-foo-functions (&rest forms)
  `(flet ((addone (x) (1+ x))
          (addtwo (x) (+ 2 x)))
     ,@forms))

(defun foo (x)
  (with-foo-functions
   (addtwo x)))

(defun bar (x)
  (with-foo-functions
   (addone x)))

Emacs Lisp具有动态绑定。这与几乎所有其他Lisp使用的词汇绑定不同。例如,如果您尝试在Common Lisp中执行以下操作,您将收到一条错误消息,说明未定义
FOO

(defun bar ()
  (foo 10))

(flet ((foo (x) (1+ x)))
  (bar))
但是,在Emacs Lisp中,由于FOO是动态绑定的,因此当
BAR
中提供了
FOO
的绑定时,将返回11

Emacs Lisp不提供函数的词法绑定,因此为了在Emacs Lisp中实现相同的功能,您必须通过将lambda绑定到词法变量,然后使用宏隐藏
FUNCALL
,来伪造它:

(lexical-let ((foo #'(lambda (x) (1+ x))))
  (macrolet ((foo (x) `(funcall foo ,x)))
    (foo 10)))

这个问题的另一个答案建议使用宏而不是
flet
。这是可行的,但会导致不必要的代码重复。我的解决方案以每次调用函数时都必须编写
macrolet
部分或使用
funcall
为代价来防止出现这种情况。如果这是经常需要的,可以编写一个宏将所有这些内容封装在词法
flet
版本中。

Emacs Lisp具有动态绑定。这与几乎所有其他Lisp使用的词汇绑定不同。例如,如果您尝试在Common Lisp中执行以下操作,您将收到一条错误消息,说明未定义
FOO

(defun bar ()
  (foo 10))

(flet ((foo (x) (1+ x)))
  (bar))
但是,在Emacs Lisp中,由于FOO是动态绑定的,因此当
BAR
中提供了
FOO
的绑定时,将返回11

Emacs Lisp不提供函数的词法绑定,因此为了在Emacs Lisp中实现相同的功能,您必须通过将lambda绑定到词法变量,然后使用宏隐藏
FUNCALL
,来伪造它:

(lexical-let ((foo #'(lambda (x) (1+ x))))
  (macrolet ((foo (x) `(funcall foo ,x)))
    (foo 10)))

这个问题的另一个答案建议使用宏而不是
flet
。这是可行的,但会导致不必要的代码重复。我的解决方案以每次调用函数时都必须编写
macrolet
部分或使用
funcall
为代价来防止出现这种情况。如果这是经常需要的,可以编写一个宏,将所有这些内容封装在词法
flet
版本中。

Macros!我需要了解这些。我一定会记住这些——谢谢!我个人会在arglist中使用
&body forms
,在模板中使用
'@forms
。尽管我认为您的意思是说
&rest forms
,@forms
,但这是个好主意?我已将其编辑到答案中。@phils:我实际上是指&body,它在宏lambda列表中扮演与&rest相同的角色,但允许有足够意识的编辑器推断主体应该具有“类似progn”的缩进,而不是“将参数挂起到funcall”的缩进。我确实是指
,@forms
。啊,我明白了。但是Emacs lisp支持吗?elisp信息页面中没有提到它,我无法让它代替
&rest
.Macros!我需要了解这些。我一定会记住这些——谢谢!我个人会在arglist中使用
&body forms
,在模板中使用
'@forms
。尽管我认为您的意思是说
&rest forms
,@forms
,但这是个好主意?我已将其编辑到答案中。@phils:我实际上是指&body,它在宏lambda列表中扮演与&rest相同的角色,但允许有足够意识的编辑器推断主体应该具有“类似progn”的缩进,而不是“将参数挂起到funcall”的缩进。我确实是指
,@forms
。啊,我明白了。但是Emacs lisp支持吗?elisp信息页面中没有提到它,我也无法让它代替
&rest
。嗨@Elias,在Emacs Lisp中,我相信通过使用
标签
宏,函数的词法范围是允许的。但是,我用
let
定义局部变量并为其指定lambda表达式的方法是否等同于您建议的方法,用
funcall
macrolet
调用函数?。。。也许我遗漏了一个重要的概念联系。谢谢…在Emacs Lisp中,
let
标签和
flet
具有动态范围。这意味着,如果您使用这些方法中的任何一种绑定变量,那么这些变量/函数将在从其主体调用的任何函数中可用。解决方法是使用
词法let
,它伪造正确的词法绑定。这样可以防止定义泄漏。
macrolet
技巧只是提供正常的调用语义,以避免必须键入