Pointers in Common Lisp

纵饮孤独 提交于 2019-12-11 02:59:08

问题


I want to save a reference (pointer) to a part of some Data I saved in another variable:

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

I could use macros, but then there would ever be much code to be executed if I want to change some Data in the middle of a list and I am not very flexible:

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

Is it possible, to create a variable as a reference and not as a copy?


回答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)

A cons cell is a pair of pointers. car dereferences the first, and cdr dereferences the second. Your list is effectively

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

Up top where you're defining b, (cdr a) gets you that second arrow. Taking the car of that dereferences the first pointer of that second cell and hands you its value. In this case, 2. If you want to change the value of that pointer, you need to setf it rather than its value.

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



回答2:


If all you need is some syntactic sugar, try 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)))

Note, that this is strictly a compile-time thing. Anywhere (in the scope of the symbol-macrolet), where b is used as variable, it is expanded into (car (cdr a)) at compile time. As Sylwester already stated, there are no "references" in Common Lisp.

I wouldn't recommend this practice for general use, though.

And by the way: never change quoted data. Using (setf (car ...) ...) (and similar) on a constant list literal like '(1 2 3) will have undefined consequences.




回答3:


Building on what Baggers suggested. Not exactly what you are looking for but you can define setf-expanders to create 'accessors'. So lets say your list contains information about people in the for of (first-name last-name martial-status) and when someone marries you can update it as:

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


来源:https://stackoverflow.com/questions/22835755/pointers-in-common-lisp

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!