Почему своп! попробовать еще раз, даже если значение Atom не изменилось? - PullRequest
0 голосов
/ 28 октября 2018

Предположим, у меня есть следующий фрагмент (надуманного) кода Clojure:

(def c (clojure.lang.Atom. [nil nil]))
(swap! c 
   (fn [[x y]] 
       ["done", (second (swap! c (fn [[x y]] [x y])))]))

Я ожидал бы, что это будет работать следующим образом:

  1. Распаковка Clojure c найти [nil nil] и передать его внешнему fn.

  2. Внешний fn вызывает swap!, который распаковывает c для поиска [nil nil],и передает это значение во внутренний fn.

  3. Внутренний fn возвращает [nil nil].Внутренний вызов swap! меняет его на новое значение c.

  4. Внешний fn возвращает значение ["done" nil].

  5. Внешний swap! пытается compare-and-set! и видит, что текущее значение c, [nil nil], совпадает со старым значением [nil nil], поэтому он успешно заменяется ["done" nil].

Но на самом деле этот код зацикливается навсегда: внешний цикл продолжает повторяться.

Почему это так?Чего не хватает в моей ментальной модели?

1 Ответ

0 голосов
/ 28 октября 2018

Пара человек из Clojure Slack помогла мне понять, что здесь происходит (спасибо!).compare-and-set! использует identical? (т. Е. Равенство ссылок Java) для сравнения старых и новых значений атома.Каждый раз, когда я воссоздаю вектор [x y], я создаю новый объект, который не identical? для старого.Даже если я не думаю о внутреннем swap! как о чем-то мутирующем, технически это так.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...