针对lisp的SBCL处理范围有何不同?它似乎没有将范围传递给被调用的函数?

Gre*_*ans 4 lisp scope sbcl common-lisp

使用emacs或我的Android应用程序时,我运行

(defun big (num) (setf num2 5)(little num)))
(defun little (num)(+ num2 num))
Run Code Online (Sandbox Code Playgroud)

Little 愉快地接受num2但是当我在我的SBCL repl(使用sublimetext3)中运行它时它没有.

它是否正确?

没有为num2创建全局变量的解决方法是什么?

我可以传递第二个论点 (little num num2)

但是当我试图little 在列表上映射时,这不会起作用.因为mapcaring正确时我只能有一个参数?

cor*_*ump 10

请阅读§6.来自Practical Common Lisp的变量.

与Emacs Lisp不同,Common Lisp默认依赖于词法范围(Emacs Lisp 默认动态的).动态范围(即无限范围和动态范围)是通过声明特殊变量来提供的,按照惯例,它们用星号围绕它们的名称(名为"耳罩")编写,如*standard-output*.您使用defparameterdefvar声明这些变量.由于它具有全局效果,因此不应该从内部函数中使用它们; 同样,您的使用setf未在Common Lisp中定义:num2之前未在范围内声明名称的变量; 此外,即使它确实如此,对局部变量使用全局/特殊变量也是不好的风格.

动态范围

使用特殊变量,您可以在本地重新绑定标准输出:只有当代码位于let绑定体内时,新值才可见:

(let ((*standard-output* *error-output*))
  (print "Stream redirection"))
Run Code Online (Sandbox Code Playgroud)

默认情况下,print写入绑定到的流*standard-output*; 这里,流本地绑定到给定的流*error-output*.一旦你逃脱let,*standard-output*恢复到它以前的值(想象有一个堆栈).

词汇范围

使用词法范围,您的代码只能访问在代码周围的文本(以及全局范围)中可见的绑定,并且范围是无限的:即使在代码返回后,也可以访问绑定(有时是间接的)的let:

(let ((closure
        (let ((count 0))
          (lambda () (print (incf count))))))
  (funcall closure)
  (funcall closure))

;; prints:
;; 1
;; 2
Run Code Online (Sandbox Code Playgroud)

lambda表达式创建一个闭包,它捕获名为的变量count.每次调用它时,它都会增加count变量并打印出来.如果再次计算相同的代码,则定义另一个闭包并创建另一个具有相同名称的变量.

Mapcar

因为mapcaring正确时我只能有一个参数?

不完全是; 通过调用的函数mapcar应该能够尽可能多元素的数量至少接受列表被赋予它(和它应该也不会要求更具强制性参数):

(mapcar (lambda (x y) (* x y))
        '(1 2 3)
        '(0 3 6))
=> (0 6 18)

(mapcar #'list '(1 2) '(a b) '(+ /))
=> ((1 a +) (2 b /))
Run Code Online (Sandbox Code Playgroud)

该函数也可以是闭包,并且可以使用特殊变量.

......有一个封闭物

(defun adder (x)
  (lambda (y) (+ x y)))

(mapcar (adder 10) '(0 1 2))

=> (10 11 12)
Run Code Online (Sandbox Code Playgroud)

adder功能需要一个数x,并返回它接受若干封闭y并返回(+ x y).

......带有特殊变量

如果您更喜欢动态范围,请使用耳罩并为其指定一个有意义的名称:

(defparameter *default-offset* 0)
Run Code Online (Sandbox Code Playgroud)

......并定义:

(defun offset (x)
  (+ x *default-offset*))
Run Code Online (Sandbox Code Playgroud)

你也可以mapcar:

(let ((*default-offset* 20))
  (mapcar #'offset '(1 2 3)))

=> (21 22 23)
Run Code Online (Sandbox Code Playgroud)

正如jkiiski在评论中所说,你也可以(declare (special ...))在通常放置声明的位置(当输入a let,a defun,...时)声明特殊变量 .您也可以使用特殊运算符progv.这对于具有"不可见"变量非常有用,这些变量仅由一组函数知道以交换信息.你很少需要它们.