【问题标题】:Lisp / parameter-passing [closed]Lisp /参数传递[关闭]
【发布时间】:2017-11-17 09:01:35
【问题描述】:

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

阅读这部分:

认为实用! ..................... 因此,要执行您想要的操作,代码需要 a) 在范围内或 b) 可以访问范围内的函数。

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

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

其次,我实际上如何利用提供的两块代码来获得所需的结果?

提前感谢您提供任何相关提示。

【问题讨论】:

  • “期望的结果”是什么?事实上,你在问什么问题?
  • 基本上,您只能通过调用关闭一组变量(或改变字段、数组)的闭包来直接(范围)或间接设置您有权访问的变量.阅读gigamonkeys.com/book/variables.html

标签: lisp parameter-passing common-lisp


【解决方案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 的绑定通过调用捕获它的函数来修改。

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

(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 函数的重新实现,它们使用了这个:

(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 更容易阅读。它的工作方式相同:

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

顺便说一句,您当然可以捕获表达式,而不仅仅是变量绑定,只要 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)

【讨论】:

    猜你喜欢
    • 2017-07-14
    • 1970-01-01
    • 1970-01-01
    • 2017-05-25
    • 2013-05-24
    • 1970-01-01
    • 1970-01-01
    • 2021-02-15
    • 2019-03-21
    相关资源
    最近更新 更多