Clojure: удалить элемент из ссылки? - PullRequest
1 голос
/ 25 июня 2019

Я создал ссылку ref "people" ниже и хочу, чтобы функция delete-person удаляла элемент из структуры данных в транзакции.

(defrecord Person [name favorite-color])

(def people (ref ()))

(defn add-person [new-person]
  (dosync
    (alter people conj new-person)))

(add-person (Person. "Joe" "Red"))
(add-person (Person. "Sam" "Blue"))

;; how do I make this function work? 
;; would @people (destructured) have to be the second argument to filter? 
(defn delete-person [name-to-delete]
  "Delete named person from ref"
  (dosync
    (alter people filter #(not= (:name %) name-to-delete))))

(delete-person "Joe")

IllegalArgumentException Don't know how to create ISeq from: 
user$delete_person$fn__1407$fn__1408  clojure.lang.RT.seqFrom (RT.java:542)

Функция ниже работает, потому что я фильтрую по деструктурированной ссылке, но как мне сделать это в транзакции, чтобы изменить данные?

   (filter #(not= (:name %) "Sam") @people)
=> (#user.Person{:name "Joe", :favorite-color "Red"})

1 Ответ

4 голосов
/ 25 июня 2019

Как говорит ошибка, вы пытаетесь выполнить итерацию функции. Это происходит потому, что когда вы пишете:

(alter people filter #(not= (:name %) name-to-delete))

Развернутый people становится аргументом first для filter, а не последним.

Вам нужно будет использовать полный fn или partial:

(alter people
    (fn [ps] (filter #(not= (:name %) name-to-delete) ps)))

Или

(alter people
    (partial filter #(not= (:name %) name-to-delete))) 

Они заставляют alter передавать развернутый people в качестве последнего аргумента filter, а не неявно в качестве первого.


Я отмечу, хотя:

  • Как упоминалось в комментариях @cfrick, использование ленивых последовательностей в транзакции может потенциально вызывать проблемы. Я не могу придумать сценарий, где это произойдет, но он чувствует неправильным. Можно утверждать, что реализация отложенной последовательности является побочным эффектом, и побочные эффекты не должны иметь место в транзакции, поскольку транзакции могут выполняться несколько раз в случае конфликта. Многочисленные реализации не должны вызывать проблемы, но я не могу однозначно сказать, что это безопасно (честно говоря, я никогда не использую ref s).

  • Убедитесь, что вам действительно нужны ref s и транзакции здесь. Транзакции предназначены для тех случаев, когда вам нужно упорядочить несколько изменений данных и иметь возможность отследить, когда соответствующие данные были изменены в процессе транзакции. Если вам просто нужен простой изменяемый контейнер, atom намного проще.

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