Common Lisp中的指针

时间:2014-04-03 11:10:37

标签: pointers lisp common-lisp

我想将参考(指针)保存到我保存在另一个变量中的某些数据的一部分:

(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")))

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

3 个答案:

答案 0 :(得分:7)

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)

答案 1 :(得分:4)

如果您只需要一些语法糖,请尝试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中没有“引用”。

但我不推荐这种做法用于一般用途。

顺便说一下:永远不要改变引用的数据。在(setf (car ...) ...)这样的常量列表文字上使用'(1 2 3)(和类似的)会产生不明确的后果。

答案 2 :(得分:1)

以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")