在clisp中调用flet或labels函数

在clisp中调用flet或labels函数,lisp,common-lisp,Lisp,Common Lisp,I通用lisp(clisp-2.49)的新版本 我可以从不同的外部函数调用flet或labels函数吗? 如果是,怎么做?(在源文件中) 除了最后一个print语句外,此代码可以工作,在该语句中,它的作用域丢失到最后一行的f(n) (labels ((f (n) (+ n 10))) (print(f 5))) (print (f 2)) 否。 由创建的函数和宏 是 局部,即它们只存在于表单内部,就像变量一样 受当地法律约束 如果需要在函数之外引用它们,则需要使用 /

I通用lisp(clisp-2.49)的新版本

我可以从不同的外部函数调用
flet
labels
函数吗? 如果是,怎么做?(在源文件中)

除了最后一个print语句外,此代码可以工作,在该语句中,它的作用域丢失到最后一行的
f(n)

(labels ((f (n)
         (+ n 10)))
  (print(f 5)))

(print (f 2))
否。

由创建的函数和宏 是 局部,即它们只存在于表单内部,就像变量一样 受当地法律约束

如果需要在函数之外引用它们,则需要使用 /

另一方面,在
flet
中可以有许多表单:

(flet ((logger (format-string &rest args)
         (apply #'format t format-string args)
         (fresh-line)))
  (defun f1 (x)
    (logger "Called f1 on ~S" x)
    (- x))
  (defun f2 (x)
    (logger "Called f2 on ~S" x)
    (1+ x)))
> (f1 10)
Called f1 on 10
==> -10
> (f2 4)
Called f2 on 4
==> 5
> (f1 (f2 (f1 5)))
Called f1 on 5
Called f2 on -5
Called f1 on -4
==> 4
您只能在
flet
主体内使用
logger
(在
f1
f2
)而不能在
flet
主体外使用

由创建的函数和宏 是 局部,即它们只存在于表单内部,就像变量一样 受当地法律约束

如果需要在函数之外引用它们,则需要使用 /

另一方面,在
flet
中可以有许多表单:

(flet ((logger (format-string &rest args)
         (apply #'format t format-string args)
         (fresh-line)))
  (defun f1 (x)
    (logger "Called f1 on ~S" x)
    (- x))
  (defun f2 (x)
    (logger "Called f2 on ~S" x)
    (1+ x)))
> (f1 10)
Called f1 on 10
==> -10
> (f2 4)
Called f2 on 4
==> 5
> (f1 (f2 (f1 5)))
Called f1 on 5
Called f2 on -5
Called f1 on -4
==> 4
您只能在
flet
主体内使用
logger
(在
f1
f2
内,但不能在
flet
外使用

我可以从不同的外部函数调用flet或labels函数吗

对!!正如其他人所提到的,
flet
定义是本地的。但价值的范围是无限的。也就是说,只要Lisp系统中的“某物”指向它,它的价值就会无限期地保留下来

但您可能会问,如果词法范围限制拒绝您在函数外部使用
flet
的名称,那么该怎么做?以下将说明:

(defun my-closure ()
  (let ((i 5))
    (flet ((my-flet ()
         (setf i (+ i 1))))
      #'my-flet)))

;; Assign the returned value (a closure) to the 'global' special
;; variable global-my-closure
(defparameter global-my-closure (my-closure))

;; Call it *without* using the #' style prefix that you would use for
;; globally bound functions.  This is a special variable whose value
;; happens to be that of a function.
(funcall global-my-closure)
6
(funcall global-my-closure)
7
(funcall global-my-closure)
8
注意,这是一个非常强大的概念。有史以来最好的编程书籍之一,《计算机程序的结构和解释》使用相关的Lisp语言Scheme详细探讨了这个主题,Scheme的语法稍微方便一些,可以用来操作闭包

我可以从不同的外部函数调用flet或labels函数吗

对!!正如其他人所提到的,
flet
定义是本地的。但价值的范围是无限的。也就是说,只要Lisp系统中的“某物”指向它,它的价值就会无限期地保留下来

但您可能会问,如果词法范围限制拒绝您在函数外部使用
flet
的名称,那么该怎么做?以下将说明:

(defun my-closure ()
  (let ((i 5))
    (flet ((my-flet ()
         (setf i (+ i 1))))
      #'my-flet)))

;; Assign the returned value (a closure) to the 'global' special
;; variable global-my-closure
(defparameter global-my-closure (my-closure))

;; Call it *without* using the #' style prefix that you would use for
;; globally bound functions.  This is a special variable whose value
;; happens to be that of a function.
(funcall global-my-closure)
6
(funcall global-my-closure)
7
(funcall global-my-closure)
8

注意,这是一个非常强大的概念。有史以来最好的编程书籍之一,《计算机程序的结构和解释》使用相关的Lisp语言Scheme详细探讨了这一主题,Scheme有一种更方便的语法来操作闭包。

与Earl D的答案相关,您可以这样做

(defmacro define-function (name v)
  `(progn
     (setf (fdefinition ',name) ,v)
     ',name))
然后

我会做你认为应该做的事


这与
(let…(defun…)
的情况稍有不同:在这种情况下,定义宏(
defun
)不在顶层,即使
let
在顶层,这可能会导致编译时出现各种毛发。

与Earl D的答案相关,您可以这样做

(defmacro define-function (name v)
  `(progn
     (setf (fdefinition ',name) ,v)
     ',name))
然后

我会做你认为应该做的事


这与
(let…(defun…)
的情况稍有不同:在这种情况下,定义宏(
defun
此处)不在顶层,即使
let
是,编译东西时,这可能会导致各种各样的问题。

FLET
/
标签定义的函数只在词法范围内可见,尽管您可以将它们作为值传递到它之外,这些值可以用
FUNCALL
/
应用
(例如
(FUNCALL(FLET((f():foo))#'f))
).使用
FLET
/
标签定义的函数仅在词法范围内可见,尽管您可以将它们作为值传递到词法范围之外,这些值可以通过
FUNCALL
/
应用调用(例如
(FUNCALL(FLET((f():foo))#'f))
)。