【问题标题】:Pointers in Common LispCommon Lisp 中的指针
【发布时间】:2014-04-03 11:10:36
【问题描述】:

我想保存一个引用(指针)到我保存在另一个变量中的一些数据的一部分:

(let ((a (list 1 2 3)))
  (let ((b (car (cdr a)))) ;here I want to set b to 2, but it is set to a copy of 2
    (setf b 4))
  a) ;evaluates to (1 2 3) instead of (1 4 2)

我可以使用宏,但是如果我想更改列表中间的一些数据并且我不是很灵活,那么将有很多代码要执行:

(defparameter *list* (create-some-list-of-arrays))
(macrolet ((a () '(nth 1000 *list*)))
  (macrolet ((b () `(aref 100 ,(a))))
    ;; I would like to change the macro a here if it were possible
    ;; but then b would mean something different
    (setf (b) "Hello")))

是否可以创建一个变量作为引用而不是副本?

【问题讨论】:

  • (let ((a (list 1 2 3))) (setf (second a) 4) a) 有什么问题?
  • 我强烈推荐阅读gigamonkeys.com/book/variables.html 并关注值、变量和位置的细节。抱歉,如果您不是该语言的新手,但如果您是该语言的新手,请记住,其他语言的映射技术不一定会给您提供好的或快速的代码。
  • 您可能会对How do I globally change a variable value within function in lisp 的答案感兴趣,该答案讨论了 C 指针、通过结构(包括 cons 单元格)的间接寻址、通用引用和模拟 C 样式指针。问题并不完全相同,但我认为答案可能就是您所需要的。
  • 第一个代码 sn-p 有未定义的行为。使用引号定义的列表是常量,修改常量的效果是未定义的。如果要修改列表,请使用列表创建它

标签: pointers lisp common-lisp


【解决方案1】:
cl-user> (let ((a '(1 2 3)))
           (let ((b (car (cdr a))))
             (setf b 4))
           a)
;Compiler warnings :
;   In an anonymous lambda form: Unused lexical variable B
(1 2 3)

cons 单元是一对指针。 car 取消引用第一个,cdr 取消引用第二个。你的清单是有效的

  a -> [ | ] -> [ | ] -> [ | ] -> NIL
        |        |        |
        1        2        3

在您定义b 的顶部,(cdr a) 为您提供第二个箭头。取car 会取消引用第二个单元格的第一个指针并将其值交给您。在这种情况下,2。如果你想改变那个指针的值,你需要setf它而不是它的值。

cl-user> (let ((a '(1 2 3)))
           (let ((b (cdr a)))
             (setf (car b) 4))
           a)
(1 4 3)

【讨论】:

    【解决方案2】:

    如果你只需要一些语法糖,试试symbol-macrolet

    (let ((a (list 1 2 3 4)))
      (symbol-macrolet ((b (car (cdr a))))
        (format t "~&Old: ~S~%" b)
        (setf b 'hello)
        (format t "~&New: ~S~%" b)))
    

    请注意,这严格来说是编译时的事情。任何地方(在symbol-macrolet 的范围内),其中b 用作变量,它在编译时扩展为(car (cdr a))。正如 Sylwester 已经说过的,Common Lisp 中没有“引用”。

    不过,我不建议将这种做法用于一般用途。

    顺便说一句:永远不要更改引用的数据。在像'(1 2 3) 这样的常量列表文字上使用(setf (car ...) ...)(和类似的)将产生未定义的后果。

    【讨论】:

      【解决方案3】:

      以 Baggers 的建议为基础。不完全是您要查找的内容,但您可以定义 setf-expanders 来创建“访问器”。因此,假设您的列表包含有关(名字姓氏军事状态)中的人的信息,当有人结婚时,您可以将其更新为:

      (defun marital-status (person)
        (third person))
      
      (defun (setf marital-status) (value person)
        (setf (third person) value))
      
      (let ((person (list "John" "Doe" "Single")))
        (setf (marital-status person) "Married")
        person)
      ;; => ("John" "Doe" "Married")
      

      【讨论】:

        猜你喜欢
        • 2016-06-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-08-06
        相关资源
        最近更新 更多