Reputation: 872
I created the ref "people" below, and want the function delete-person to delete an item from the data structure within a transaction.
(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)
The function below works because I filter on the destructured ref, but how do I do it in a transaction to mutate the data?
(filter #(not= (:name %) "Sam") @people)
=> (#user.Person{:name "Joe", :favorite-color "Red"})
Upvotes: 1
Views: 88
Reputation: 45742
As there error says, you're trying to iterate a function. This is coming about because when you write:
(alter people filter #(not= (:name %) name-to-delete))
The unwrapped people
becomes the first argument to filter
, not the last.
You'll need to use an full fn
, or use partial
:
(alter people
(fn [ps] (filter #(not= (:name %) name-to-delete) ps)))
Or
(alter people
(partial filter #(not= (:name %) name-to-delete)))
These make alter
pass the unwrapped people
as the last argument to filter
, instead of implicitly as the first.
I'll note though:
As @cfrick brought up in the comments, using lazy sequences in a transaction may have the potential to cause problems. I can't offhand think of a scenario where it would, but it feels wrong. It could be argued that the realization of a lazy sequence is a side effect, and side effects shouldn't take place in a transaction, since transactions may run multiple times in the event of a conflict. Multiple realizations shouldn't cause a problem, but I can't say definitively that it's safe (honestly, I never use ref
s).
Make sure you actually need ref
s and transactions here. Transactions are for when you need to sequence multiple alterations to data, and need to be able to catch when the data involved has been changed part way through a transaction. If you just need a simple mutable container though, atom
are much simpler.
Upvotes: 4