Function 公共Lisp中函数之间的循环依赖关系

Function 公共Lisp中函数之间的循环依赖关系,function,lisp,common-lisp,Function,Lisp,Common Lisp,是否可以在公共LISP中定义两个相互调用的函数而不接收样式警告?我解决这个问题的最好办法是把其中一个函数作为第二个函数的参数,但我觉得这个想法并不优雅。这当然是可能的。您只需小心不要创建无限循环。因此,这里同样适用于递归(您需要一个终止案例) 顺便说一下,当函数调用未定义的函数时,SBCL会发出警告 波兹德罗维尼亚 这当然是可能的。您只需小心不要创建无限循环。因此,这里同样适用于递归(您需要一个终止案例) 顺便说一下,当函数调用未定义的函数时,SBCL会发出警告 波兹德罗维尼亚 考虑到defun

是否可以在公共LISP中定义两个相互调用的函数而不接收样式警告?我解决这个问题的最好办法是把其中一个函数作为第二个函数的参数,但我觉得这个想法并不优雅。

这当然是可能的。您只需小心不要创建无限循环。因此,这里同样适用于递归(您需要一个终止案例)

顺便说一下,当函数调用未定义的函数时,SBCL会发出警告


波兹德罗维尼亚

这当然是可能的。您只需小心不要创建无限循环。因此,这里同样适用于递归(您需要一个终止案例)

顺便说一下,当函数调用未定义的函数时,SBCL会发出警告


波兹德罗维尼亚

考虑到
defun
不需要出现在顶层,您可以以一种稍微复杂的方式定义两个相互递归的函数,而不需要样式警告(请参阅):

X3J13于1989年3月投票(定义-宏-非顶级)澄清,虽然定义表单通常出现在顶级,但将其置于非顶级上下文中是有意义的
defun
必须在封闭词法环境中定义函数,而不是在空词法环境中定义函数

例如,使用特殊运算符
labels
(),可以定义相互递归的函数:

CL-USER> (labels ((f (x)
                    (cond ((> x 0) (g (1- x)))
                          ((= x 0) x)
                          (t (g (1+ x)))))
                  (g (y)
                    (if (= y 0)
                        0
                        (f y))))
           (defun f(x) (funcall #'f x))
           (defun g(x) (funcall #'g x)))
G
CL-USER> (f 3)
0
CL-USER> (g 3)
0

考虑到
defun
不需要出现在顶层,您可以以一种稍微复杂的方式定义两个相互递归的函数,而不需要样式警告(请参见):

X3J13于1989年3月投票(定义-宏-非顶级)澄清,虽然定义表单通常出现在顶级,但将其置于非顶级上下文中是有意义的
defun
必须在封闭词法环境中定义函数,而不是在空词法环境中定义函数

例如,使用特殊运算符
labels
(),可以定义相互递归的函数:

CL-USER> (labels ((f (x)
                    (cond ((> x 0) (g (1- x)))
                          ((= x 0) x)
                          (t (g (1+ x)))))
                  (g (y)
                    (if (= y 0)
                        0
                        (f y))))
           (defun f(x) (funcall #'f x))
           (defun g(x) (funcall #'g x)))
G
CL-USER> (f 3)
0
CL-USER> (g 3)
0

是的,当然是,它不需要任何特殊的魔法

简单地定义一个,然后定义另一个。如果在REPL中执行此操作,或者通过有选择地评估文件中的各个定义,或者通过加载文件源执行此操作,则在定义第一个函数时,您可能会收到警告,直到定义第二个函数为止(因此,您仅在第一次定义第一个函数时才会收到此警告):

实际上,在SBCL和CMUCL等纯编译器实现中,您可能只会收到类似的警告。其他实现也没有理由不发出警告:它们通常不会发出警告,因为这样的警告往往令人讨厌。假设您希望在确实缺少定义时看到警告,那么在仅编译器的实现中很难避免它们

如果您只是将这两个函数放入一个文件中并编译它们:

cl-user> (compile-file "/tmp/x.lisp" :load t)
; Evaluation aborted on #<unknown-keyword-argument {100219F653}>.
cl-user> (load (compile-file "/tmp/x.lisp"))
; compiling file "/tmp/x.lisp" (written 21 APR 2020 04:35:27 PM):
; compiling (defun foo ...)
; compiling (defun bar ...)

; wrote /tmp/x.fasl
; compilation finished in 0:00:00.002
t
cl-user> (foo '(1 2 3 4))
1
这会将编译器发出的警告延迟到表单末尾,此时所有警告都没有。我认为这是不可靠的(我认为它在其他实现中是无害的,但他们仍然可以发出警告)


(请注意,上面的每个摘录都来自一个新的SBCL。)

是的,当然是,它不需要任何特殊的魔法

简单地定义一个,然后定义另一个。如果在REPL中执行此操作,或者通过有选择地评估文件中的各个定义,或者通过加载文件源执行此操作,则在定义第一个函数时,您可能会收到警告,直到定义第二个函数为止(因此,您仅在第一次定义第一个函数时才会收到此警告):

实际上,在SBCL和CMUCL等纯编译器实现中,您可能只会收到类似的警告。其他实现也没有理由不发出警告:它们通常不会发出警告,因为这样的警告往往令人讨厌。假设您希望在确实缺少定义时看到警告,那么在仅编译器的实现中很难避免它们

如果您只是将这两个函数放入一个文件中并编译它们:

cl-user> (compile-file "/tmp/x.lisp" :load t)
; Evaluation aborted on #<unknown-keyword-argument {100219F653}>.
cl-user> (load (compile-file "/tmp/x.lisp"))
; compiling file "/tmp/x.lisp" (written 21 APR 2020 04:35:27 PM):
; compiling (defun foo ...)
; compiling (defun bar ...)

; wrote /tmp/x.fasl
; compilation finished in 0:00:00.002
t
cl-user> (foo '(1 2 3 4))
1
这会将编译器发出的警告延迟到表单末尾,此时所有警告都没有。我认为这是不可靠的(我认为它在其他实现中是无害的,但他们仍然可以发出警告)

(请注意,上面的每个摘录都来自一个新的SBCL。)

Common Lisp定义编译单元,您甚至可以使用手动指定编译单元的范围

例如,当您调用时,整个文件表示一个编译单元:编译器通常会在文件末尾延迟警告,这意味着如果您正确定义了两个相互递归的函数,则不会出现警告

另一种可能性是执行远期申报:

(declaim (ftype function f))
(defun g () (f))
(defun f () (g))
第一个
declaim
表示
f
将被视为fbound(符号绑定在函数名称空间中),在编译期间禁止在使用点发出警告。

Common Lisp定义编译单元,甚至可以使用手动指定编译单元的范围

例如,当您调用时,整个文件表示一个编译单元:编译器通常会在文件末尾延迟警告,这意味着如果您正确定义了两个相互递归的函数,则不会出现警告

另一种可能性是执行远期申报:

(declaim (ftype function f))
(defun g () (f))
(defun f () (g))
第一个
declaim
表示
f
将被视为fbound(符号绑定在函数名称空间中),在编译期间禁止在使用点发出警告