Common lisp Common Lisp--是否可以定义;unlet";?
我编写的大多数函数都非常小,而且递归函数相对较少。Common Lisp是否提供了一种通过“解除绑定”函数体中的函数名来防止递归的方法。或者,它是否提供了一种方法来解除符号的函数值绑定,以便我可以滚动自己的显式非递归Common lisp Common Lisp--是否可以定义;unlet";?,common-lisp,Common Lisp,我编写的大多数函数都非常小,而且递归函数相对较少。Common Lisp是否提供了一种通过“解除绑定”函数体中的函数名来防止递归的方法。或者,它是否提供了一种方法来解除符号的函数值绑定,以便我可以滚动自己的显式非递归defun 我希望能够做类似于下面的事情,可能隐藏在宏后面 (defun non-recursive-func (arg) (unflet (non-recursive-func) (+ (first arg) (second arg)))) 今天我无意中编写了一些错误
defun
我希望能够做类似于下面的事情,可能隐藏在宏后面
(defun non-recursive-func (arg)
(unflet (non-recursive-func)
(+ (first arg) (second arg))))
今天我无意中编写了一些错误代码,其中包装函数委托给它自己而不是unwrapped函数,这让我意识到使用一些编译时机制防止递归可能是有用的
(defun fcompose-2 (f g)
(lambda (x) (funcall f (funcall g x))
(defun fcompose (&rest args)
(reduce #'fcompose-2 args))
除了我无意中为fcompose
的定义编写了以下内容之外
(defun fcompose (&rest args)
(reduce #'fcompose args))
自然会导致堆栈溢出。那么:
(defmacro defun* (name (&rest args) &body body)
`(defun ,name ,args
(flet ((,name ,args
(declare (ignore ,@args))
(error "~a is defined with defun* and cannot be called from itself" ',name)))
,@body)))
这在函数范围中添加了一个内部绑定,如果在正文中使用该绑定,则只会发出错误信号,您可以将defun*
定义替换为defun
,用于生产 那么:
(defmacro defun* (name (&rest args) &body body)
`(defun ,name ,args
(flet ((,name ,args
(declare (ignore ,@args))
(error "~a is defined with defun* and cannot be called from itself" ',name)))
,@body)))
这在函数范围中添加了一个内部绑定,如果在正文中使用该绑定,则只会发出错误信号,您可以将
defun*
定义替换为defun
,用于生产 我曾试图想出其他方法来实现这一点,但函数名永远不会出现在作用域中,但我认为,如果您在编译时捕获到错误,而不是flet
,则这种方法最不可能混淆乐观者。还可能希望使用alexandria:parse body
正确地获取声明和文档,并。。。这在现实世界中可能不值得。@SteveLosh编译时如何捕获(someop somefunnamebinding)
?这就像修复暂停问题。(macrolet((foo(&args)(错误“意外递归”))(foo 1 2))
将在宏扩展时发出错误信号(编译时会发生)。它不会捕获所有内容,比如(bar#'foo)
,因此可能也值得在运行时使用flet
来捕获这些内容。不,我收回它,您真的不需要flet
<正文中的代码>(foo…)将在宏扩展时发出错误信号(funcall#'foo)
也会发出错误信号,因为foo
是一个宏,而不是一个函数(至少在SBCL和CCL中——规范技术上允许实现出于性能原因而不发信号)。它不会把你从所有事情中拯救出来,例如(funcall(从字符串“foo”读取))
,但它可以捕获父级在编译时寻找的大部分内容。我试图想出其他方法来实现这一点,但我认为这种方法最不可能混淆乐观主义者,如果您使用macrolet
而不是flet
,则可以在编译时捕获错误。还可能希望使用alexandria:parse body
正确地获取声明和文档,并。。。这在现实世界中可能不值得。@SteveLosh编译时如何捕获(someop somefunnamebinding)
?这就像修复暂停问题。(macrolet((foo(&args)(错误“意外递归”))(foo 1 2))
将在宏扩展时发出错误信号(编译时会发生)。它不会捕获所有内容,比如(bar#'foo)
,因此可能也值得在运行时使用flet
来捕获这些内容。不,我收回它,您真的不需要flet
<正文中的代码>(foo…)将在宏扩展时发出错误信号(funcall#'foo)
也会发出错误信号,因为foo
是一个宏,而不是一个函数(至少在SBCL和CCL中——规范技术上允许实现出于性能原因而不发信号)。它不会把你从所有事情中解救出来,例如(funcall(从字符串“foo”中读取)
,但它可以在编译时捕获父级正在查找的大部分内容。