2017-06-15 100 views
0

为了解决我在使用Common Lisp时遇到的一些问题,我浏览了网络并发现: Variable references in lisp 这与我的问题非常相关。Lisp /参数传递

阅读这一部分:

想想功能! .................. 因此,要做你想做的事,代码需要a)在范围内或b)可以访问范围内的函数。

我想弄清楚它,但事情并不清楚。

首先,我不确定a)和b)在最后一句中指的是什么。

第二我如何实际上使用提供的两个代码块来获得所需的结果?

在此先感谢您的任何相关提示。

+2

什么是 '期望的结果'?事实上,你问什么问题? – tfb

+0

基本上,您只能通过调用关闭一组变量(或变异字段,数组)的闭包来直接(范围)或间接地设置您有权访问的变量。阅读http://www.gigamonkeys.com/book/variables.html – coredump

回答

1

我仍然无法弄清楚你问的是什么问题,但我想你想知道如何在功能中的一个范围内修改绑定,而这个功能看不到绑定。所以这是对这个问题的回答。

首先要理解的是,现代编程语言中的范围非常简单:如果您可以看到绑定(名称和值之间的关联),那么您可以访问该绑定,并且如果它是可变的,则可以进行变异它。早期的现代编程语言有许多神秘的规则,这些规则基于很久以前在小型计算机上的易用性(我们都被PDP-11的遗留问题所诅咒),但是现代的编程语言扫除了所有这些。在这个意义上,Common Lisp大多是一种现代编程语言。

因此,您需要做的是以某种方式捕获绑定,然后将捕获的绑定传递给您要调用的任何函数,以便在其中进行访问或变异。捕获绑定的方式是使用函数。

所以,在这里是如何做到这一点的CL一个简单的例子:

(defun foo (orig new) 
    (let ((x orig)) 
    (bar (lambda (&optional (value nil valuep)) 
      (if valuep 
       (setf x value) 
      x)) 
     new) 
    x)) 

(defun bar (c new) 
    (format t "~&initially ~S~%" (funcall c)) 
    (funcall c new) 
    (format t "~&then ~S~%" (funcall c))) 

在这段代码被第一个参数创建bar功能访问的x的结合,并且是这么写的所以不带任何参数调用它将返回绑定的值,而用参数调用它将设置值。下面是在行动:

CL-USER 5 > (foo 1 2) 
initially 1 
then 2 
2 

所以你可以看到这个作品:的x绑定是通过调用其捕获它的功能修改。我们可以避免所有这些显式的funcall s和lambda s(我们可以避免前者在Lisp-1中,但它仍然不是很好)。但是,这在语法上很笨拙:如果我们可以避免所有这些显式的funcall s和lambda s因此,这里的一些代码做(它的解释如下)认为:

(defmacro capture (binding) 
    "Capture a binding" 
    (let ((value (make-symbol "VALUE")) 
     (valuep (make-symbol "VALUEP"))) 
    `(lambda (&optional (,value nil ,valuep)) 
     (if ,valuep 
      (setf ,binding ,value) 
     ,binding)))) 

(defun captured (c &optional (value nil valuep)) 
    "Return the value of a captured binding, or set it" 
    (if valuep 
     (funcall c value) 
    (funcall c))) 

(defsetf captured captured) 

OK,所以宏观capture只是语法糖它创建等同于一个原代码的功能。它必须是一个宏,因为该功能需要在它捕获的绑定范围内创建。

captured是那么平凡函数刚刚调用由capture以适当的方式建立的功能:所以与其说(funcall c)我们可以说(captured c)

最后defsetf窗体教setf如何设置捕获的绑定,所以(setf (captured x) y)将工作。

这里是其使用上述foobar功能重新实现:

(defun foo (orig new) 
    (let ((x orig)) 
    (bar (capture x) new) 
    x)) 

(defun bar (c new) 
    (format t "~&initially ~S~%" (captured c)) 
    (setf (captured c) new) 
    (format t "~&then ~S~%" (captured c))) 

我认为这是明显的,这是更好的比所有明确funcall S和lambda S上方阅读。它的工作方式相同:

CL-USER 6 > (foo 1 2) 
initially 1 
then 2 
2 

顺便说一句,你可以捕捉expresssions,不只是变量绑定,当然,只要setf知道该怎么跟他们做的(只要它们是什么呼叫 '地方'):

(defun fish (l) 
    (bone (capture (car l))) 
    l) 

(defun bone (c) 
    (setf (captured c) 'bone)) 

现在

CL-USER 13 > (fish (list 1 2)) 
(bone 2)