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
技巧只是提供正常的调用语义,以避免必须键入