首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Lisp /参数传递

Lisp /参数传递
EN

Stack Overflow用户
提问于 2017-06-15 03:01:33
回答 1查看 1.2K关注 0票数 0

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

阅读本部分:

认为有效!.因此,要做您想做的事情,代码需要( a)在作用域中,或者( b)可以访问作用域中的函数。

我想弄明白,但事情还不清楚。

首先,我不知道最后一句中所指的是什么( a)和b)。

第二,如何实际使用所提供的两段代码来获得所需的结果?

谢谢您提供的任何相关建议。

EN

回答 1

Stack Overflow用户

发布于 2017-06-15 07:15:16

我仍然不知道您在问什么问题,但是我想您想知道如何在无法看到绑定的函数范围内修改绑定。下面是这个问题的答案。

首先要理解的是,现代编程语言中的范围非常简单:如果您可以看到绑定(名称和值之间的关联),那么您可以访问它,如果它是可变的,则可以对其进行变异。以前的现代编程语言有各种各样的神秘规则,这些规则限制了这一点,因为很久以前,在微型计算机上实现起来很容易(我们都被PDP-11的遗产所诅咒),但是现代的编程语言把这一切都扫除了。从这个意义上讲,通用Lisp主要是一种现代编程语言。

因此,您需要做的是以某种方式捕获绑定,然后将捕获的绑定传递到您想要调用的任何函数中,在那里可以访问或变异绑定。捕获绑定的方式是使用函数。

因此,这里有一个简单的例子,说明如何在CL中这样做:

代码语言:javascript
运行
复制
(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的绑定,并且是这样编写的,因此不带参数调用它将返回绑定的值,而用参数调用它将设置值。以下是实际行动:

代码语言:javascript
运行
复制
CL-USER 5 > (foo 1 2)
initially 1
then 2
2

所以您可以看到这是可行的:x的绑定是通过调用捕获它的函数来修改的。

但这在语法上是笨拙的:如果我们能够避免所有这些显式的funcalls和lambdas (我们可以在Lisp-1中避免前者,但仍然不是很好),那就太好了。因此,这里有一些代码可以做到这一点(下面解释一下):

代码语言:javascript
运行
复制
(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)

好的,所以宏capture只是语法糖,它创建一个与原始代码中的函数相同的函数。它必须是一个宏,因为函数需要在它捕获的绑定范围内创建。

因此,captured是一个简单的函数,它只是以一种适当的方式调用capture创建的函数:因此,与其说(funcall c),不如使用(captured c)

最后,defsetf表单告诉setf如何设置捕获的绑定,这样(setf (captured x) y)就可以工作了。

下面是使用以下内容的上述foobar函数的重新实现:

代码语言:javascript
运行
复制
(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)))

我认为这显然比上面所有的显式funcalls和lambdas更好阅读。它的工作方式也是一样的:

代码语言:javascript
运行
复制
CL-USER 6 > (foo 1 2)
initially 1
then 2
2

顺便说一句,只要setf知道如何处理它们(只要它们被称为“places”),您就可以捕获高速公路,而不仅仅是变量绑定:

代码语言:javascript
运行
复制
(defun fish (l)
  (bone (capture (car l)))
  l)

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

而现在

代码语言:javascript
运行
复制
CL-USER 13 > (fish (list 1 2))
(bone 2)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44557821

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档