В Common Lisp, когда на объекты ссылаются и когда они напрямую доступны по значению? - PullRequest
0 голосов
/ 03 января 2019

Я читал этот вопрос , чтобы попытаться понять ответ.В нем конкретно говорится о передаче по ссылке, и все ответы, похоже, указывают на отсутствие поддержки передачи по ссылке.Однако этот ответ будет означать, что, хотя передача по ссылке может не поддерживаться, некоторые значения действительно доступны по ссылке.Более простой пример будет включать в себя cons клетки;Я могу передать в функцию cons-ячейку и изменить ее cdr или car на любое другое.

В конечном счете, я хотел бы знать, есть ли какое-то явное разделение между (для использования языка C #) значениями-типамии reference-types, и, если есть какой-либо способ (более удобный, чем ответ, указанный выше), рассматривать значение как ссылочный тип.

1 Ответ

0 голосов
/ 03 января 2019

Нет никакого различия: все объекты передаются по значению в Лиспе (по крайней мере, во всех Лиспах, о которых я знаю). Однако некоторые объекты изменяемые , и conses - один из таких типов. Таким образом, вы можете передать cons-ячейку в процедуру и изменить ее в этой процедуре. Таким образом, важно учитывать, являются ли объекты изменчивыми или нет.

В частности, эта (Common Lisp) функция всегда возвращает T в качестве первого значения, даже если второе значение может не иметь 0 в качестве значения car или cdr.

(defun cbv (&optional (f #'identity))
  (let ((c (cons 0 0)))
    (let ((cc c))
      (funcall f c)
      (values (eq c cc) c))))

> (cbv (lambda (c)
         (setf (car c) 1
               (cdr c) 2)))
t
(1 . 2)

Однако, поскольку Common Lisp имеет лексическую область видимости, первоклассные функции и макросы, вы можете сделать некоторую хитрость, которая заставляет его выглядеть немного, как будто происходит вызов по ссылке:

(defmacro capture-binding (var)
  ;; Construct an object which captures a binding
  `(lambda (&optional (new-val nil new-val-p))
     (when new-val-p
       (setf ,var new-val))
     ,var))

(defun captured-binding-value (cb)
  ;; value of a captured binding
  (funcall cb))

(defun (setf captured-binding-value) (new cb)
  ;; change the value of a captured binding
  (funcall cb new))

(defun cbd (&optional (f #'identity))
  (let ((c (cons 0 0)))
    (let ((cc c))
      (funcall f (capture-binding c))
      (values (eq c cc) c cc))))

А теперь:

> (cbd (lambda (b)
         (setf (captured-binding-value b) 3)))
nil
3
(0 . 0)

Если вы понимаете, как это работает, вы, вероятно, довольно много понимаете, как работают контексты и макросы в Лиспе.


Существует исключение из универсальности передачи объектов по значению в Common Lisp, которое упомянуто Райнером в комментарии ниже: экземпляры некоторых примитивных типов могут быть скопированы в некоторых обстоятельствах для эффективности. Это всегда происходит только для экземпляров определенных типов, и объекты, для которых это происходит, всегда неизменны. Чтобы справиться с этим случаем, CL предоставляет предикат равенства eql, который делает то же самое, что и eq, , за исключением , который он знает об объектах, которые может быть тайно скопирован таким образом и сравнивает их должным образом.

Таким образом, безопаснее всего использовать eql вместо eq: поскольку объекты, которые могут быть скопированы, всегда неизменны, это означает, что вы никогда не запутаетесь.

Вот пример, в котором объекты, которые вы, естественно, считаете идентичными, оказываются не такими. Учитывая это определение:

(defun compare (a b)
  (values (eq a b)
          (eql a b)))

Тогда в используемой реализации я обнаружил, что:

> (compare 1.0d0 1.0d0)
nil
t

так что плавающий ноль двойной точности не всегда равен eq сам по себе, но всегда eql сам по себе. И пытаться что-то, что кажется, должно быть то же самое:

> (let ((x 1.0d0)) (compare x x))
t
t

Так что в этом случае похоже, что вызов функции не копирует объекты, а скорее я начал с двух разных объектов, приходящих из считывателя. Однако реализации всегда разрешено копировать числа по желанию, и это вполне может быть сделано с различными настройками оптимизации.

...