Lisp中的变量和符号是否不同?

Lisp中的变量和符号是否不同?,lisp,Lisp,numberp是Lisp中的谓词,(numberp 1)按预期返回T。但是如果我只在控制台中键入numberp,它会提示变量名未定义 这两个函数和变量之间有什么区别?函数和变量位于公共Lisp中的不同名称空间中 因此,当您在预期函数的位置(即在正在计算的列表的开头)使用名称时,它会查找具有该名称的函数(或宏)。如果在需要变量的位置使用相同的名称,它将查找具有该名称的变量 在您的例子中,有一个名为numberp的函数,但没有名为numberp的变量,因此第二种情况会导致错误。这个问题已经稍微有点错

numberp
是Lisp中的谓词,
(numberp 1)
按预期返回T。但是如果我只在控制台中键入
numberp
,它会提示变量名未定义


这两个函数和变量之间有什么区别?

函数和变量位于公共Lisp中的不同名称空间中

因此,当您在预期函数的位置(即在正在计算的列表的开头)使用名称时,它会查找具有该名称的函数(或宏)。如果在需要变量的位置使用相同的名称,它将查找具有该名称的变量


在您的例子中,有一个名为numberp的函数,但没有名为numberp的变量,因此第二种情况会导致错误。

这个问题已经稍微有点错误了

我们在公共Lisp中讨论不同的事情:

  • 符号:这是Lisp中的数据结构。符号是具有名称、值、函数、包等的数据对象
在Common Lisp中,符号可以同时具有值和函数(或宏)

  • 变量是Lisp代码中值的标识符
DEFVAR和DEFPARAMETER定义了顶级变量。还有由LAMBDA、DEFUN、LET、LET*等定义的局部变量

(defun foo (i-am-a-variable) ...)

(defparameter *i-am-a-global-variable* ...)
  • 命名的函数是Lisp代码中函数的标识符。命名函数由DEFUN、DEFGENERIC和DEFMETHOD在顶层引入。还有由FLET和标签定义的局部命名函数
例如:

(defun i-am-a-function (foo) ...)

(flet ((i-am-a-function (foo) ...)) ...)
(type-of (second '(defun foo () nil)))  -->  SYMBOL
函数名和变量名是源代码中的符号。

例如:

(defun i-am-a-function (foo) ...)

(flet ((i-am-a-function (foo) ...)) ...)
(type-of (second '(defun foo () nil)))  -->  SYMBOL
让我们看看函数和变量:

(defun foo ()
  (let ((some-name 100))
    (flet ((some-name (bar) (+ bar 200)))
       (+ some-name (some-name some-name)))))
上面的代码在源代码中使用了一个变量和一个具有相同符号的函数。因为函数和变量有自己的名称空间,所以不会发生冲突

(+ some-name (some-name some-name))
这意味着我们将变量添加到变量函数调用的结果中

这样做的实际效果是,您可以执行以下操作:

(defun parent (person) ...)

(defun do-something (parent)
   (parent parent))
您不必担心局部变量名会影响全局(或局部)函数。它们只是在不同的名称空间中

在Scheme中只有一个名称空间,我们必须编写

(define (foo lst) (list 'a lst 'n))
在Common Lisp中,我们可以编写:

(defun foo (list) (list 'a list 'n))
在Common Lisp中,不需要编写
lst
而不是
list
——因为局部变量
list
和全局函数
list
之间没有冲突

访问其他命名空间

要获取存储在变量中的函数对象,可以使用
function

(let ((my-function (function numberp)))
  (funcall my-function 10))
(函数foo)
可以写成更短的
#'foo

FUNCALL
调用函数对象

OTOH,如果要在函数名称空间中存储变量中的函数对象,只有一种方法:

(setf (symbol-function 'foo) my-function)
对象必须是一个函数,而不是其他东西(数字、字符串等)。否则您将看到一个错误


这样做的副作用是,一个普通的Lisp永远不必检查在
(foo-bar)
中foo是否真的是一个函数。Scheme(可以说是一种Lisp方言)和Common Lisp之间的区别之一是,在Scheme中,变量和函数只有一个名称空间,而在CL中,有两个单独的名称空间。 因此,在Scheme中,“define”将这个名称(也是唯一的名称)设置为value assoc,而在CL中,值有“define”,函数关联有“defun”

因此,在CL中,您可以:

(define foo ...something...)
(defun foo ...somethingElse...)
迷惑读者

在该方案中,只有一个:

(define foo something)

如果这是好是坏在过去几乎是一个宗教争论…

可能最好加上这一点,以获得实际的函数
numberp
,而不调用它。CL中的语法是
#'numberp
。是的,你是对的;应该写“defvar”,并提到它只定义全局变量。