LISP局部/全局变量赋值(LISP local/global variable assignmen

2019-07-31 10:42发布

如果我们定义一个函数像

(defun foo(x)
  (setf x somevalue))

x定义为一个局部变量或全球性的? 使用SETF / q是设定值是全球性的。 如果是全球谁能告诉我如何定义Lisp的其他局部变量不是let

谢谢!

请看下面的例子

(let ((x 0)) 
  (defun foo (y) 
    (when (equal x 0) (setq x y)) 
    (when (< x y) (setq x y))
    x))

当我给一些输入到foo(foo 2)它返回2,如果我们以再次执行功能(foo 1)它仍返回2和(foo 3)返回3,本是我真正想要做的。但问题是,这怎么可能,因为如果我尝试访问变量x的功能外从CLISP终端,我无法to.If我再次访问该功能,它似乎保留了以前的值x

谢谢!

Answer 1:

要绘制平行于像C,C ++,Java或Python语言你的代码更改为“本地变量”,即使这不是一个利斯佩尔将使用(在Lisp的说法措辞将是一个地方“结合”措辞)。

您可以使用函数的参数,如你的榜样呢,或者使用一些标准格式,如:创建本地变量:

  • (let ((x 12)) ...)
  • (do ((x 0 (1+ i))) ...)
  • (dotimes (x 10) ...)
  • (loop for x from 0 to 10 do ...)

在另一方面,它可能在你实现所有的本地变量使用的参数和其他形式的根本是扩大到宏创建的。 例如:

(let ((x 10)) ...)

相当于

(funcall (lambda (x) ...) 10)

还需要注意的是确实阅读你的代码片段很可能是x是一个意义上的“全局变量”,因为它可能已被宣布为特殊:

(defvar x 12)
;; ==> x

(defun bar ()
  (format t "The value of x is ~a" x))
;; ==> bar

(defun foo (x)
  (bar))
;; ==> foo

(foo 42)
The value of x is 42
;; ==> NIL

x
;; ==> 12

如果您声明一个变量“特殊”的使用(defvar ...)将不同的处理:这就像每次使用它作为一个参数,或者您在使用它的时候(let ..)形成什么样的代码会做的是保存当前值,使用新提供的值,然后恢复你退出功能或后的值let

因此,这些变量都是“全局”(因为外功能可以看到它们),而且本地(因为你的函数后,还是让结束前值将恢复)。

标准的约定是命名与IE浏览器无论是在开始和名字一样的结尾有“耳罩”特殊变量:

(defvar *x* 12)

这有助于谁读你的代码来了解该变量是特殊的。 请注意,然而,这不是由语言授权任何名称可用于特殊变量。

没有什么类似C,C ++,Java或Python特殊变量。

关于最后一个音符setqsetf 。 事情有点棘手,因为在这里你需要了解的Lisp的较低水平,看看为什么setq是必要的。 如果你正在使用的Common Lisp,那么你应该完全忘记setq并始终使用setf

setf是将扩大到宏setq在需要时(但是也可以setq可以变成setf需要(符号宏)时,这是哪里的东西可能会比较混乱的新手)。

你的最后一个例子是“关闭”的情况。 当你定义一个函数(或有名或无名的有(lambda ...)格式)功能可以“捕获”是可见的,并随后将变量。 常常表现出一种更简单的情况下是“加法器”:

(defun adder (x)
  (lambda (y) (incf x y)))

这个函数返回将不断增加的价值传递给内部累积的功能:

(let ((f (adder 10)))
  (print (funcall f 3))
  (print (funcall f 9))
  (print (funcall f 11)))

输出将是13(10 + 3),22(13 + 9)和33(22 + 11)。

匿名函数“捕获”局部变量x ,甚至退出后,可以用它adder功能。 在如C,C ++或Java语言,当您退出所定义的变量范围的局部变量无法生存。

C ++ 11有不愿透露姓名的功能,但仍存变数,不能捕获和生存的范围(可以将它们复制到匿名函数的局部变量,但这是不一样的东西)。



Answer 2:

事实上, x是局部的作用,所以setfsetq荷兰国际集团它只是改变了局部变量x

为了回答你问题的第二部分,还有另一种方式来定义比让一个局部变量等:

(funcall (lambda (var1 var2...)
           ... use var1 var2 ...)-
   val1 val2 ...)

事实上, defun可以实现为

`(setf (symbol-function ,name) (lambda ,args ,@body))

尽管所有我检查的实现做更多的事。

此外, symbol-function的地方,您可以这样做:

(setf (symbol-function '+) (function -))

虽然这通常是一个坏主意。

你的第二个问题

发生了什么事存在着x是本地的包含范围defun 。 这不是一个全局变量。 什么你有这样做defun是创建一个闭包“捕获”的所有词汇范围的(不创建defvar / defparameter )变量在周边范围并持有到他们的未来。 如果要检查的值x ,添加其他功能

(defun get-x () x)

内部let 。 换一种方式, x是本地let的功能是在你所提供的情况是相似的:

(let ((x 3))
    (print x)
    (let ((y 7))
        (print (list x y))
        (setf x y))
    (print x))

除了内let由替换defun (这是一个lambda )。



Answer 3:

在你的代码x是一个参数的f功能,因此本地的功能。 要将呼叫setf不会产生新的变量,而是简单地将现有的本地变量的值x 。 使用setq而非setf将具有相同的行为。



文章来源: LISP local/global variable assignment