practicalli / practicalli/clojure
swap-vals! example
Nobody has claimed this yet.
- Dominant language
- Makefile
- Stars
- 117
- Forks
- 36
- PR merge metrics
- No merged PRs in 30d
Description
Is there a canonical way to construct a function that returns subsequent elements from a lazy seq, on subsequent calls?
=> (let [f (yield-elems (cycle [:foo :bar]))]
[(f) (f) (f)])
[:foo :bar :foo]
Is there something like yield-elems here?
walterl 00:36
This works, but seems somewhat cumbersome:
(defn yield-elems
[xs]
(let [xs' (atom xs)]
(fn []
(let [[x & rst] @xs']
(reset! xs' rst)
x))))
I'd probably do this:
(defn yield-elems [s]
(let [s (atom s)]
(fn [] (ffirst (swap-vals! s rest)))))
16 replies
walterl 10 hours ago
There we go! 👏
seancorfield 10 hours ago
swap-vals! is fairly new and it returns both the old and new values of the atom being swapped.
walterl 10 hours ago
It's definitely new to me 🙂
walterl 10 hours ago
Thanks for that
seancorfield 10 hours ago
Added in 1.9. I'm only just getting used to it and still forget it exists and write something more verbose with swap! etc.
walterl 10 hours ago
Any critique on my version?
seancorfield 10 hours ago
It has a race condition if two threads called f at the same time.
seancorfield 10 hours ago
Both calls to f could read @xs' and get the same value, then both could call reset! so you'd only get one element consumed from two calls.
seancorfield 10 hours ago
Pretty much any time you have both deref (@) and reset! in the same chunk of code, you can run into problems.
walterl 10 hours ago
Makes sense. Just for completeness sake, would you fix that race condition with a locking, or is there a better way?
seancorfield 10 hours ago
Even mixing deref and swap! can be problematic -- hence the addition of swap-vals!.
seancorfield 10 hours ago
The better way is swap-vals! 🙂
seancorfield 10 hours ago
Anything else isn't going to be atomic.
walterl 10 hours ago
Noted, thanks! 👍
seancorfield 10 hours ago
Also, remember that the function applied to an atom (in swap! or swap-vals!) can be called more than once if the STM needs to retry.
seancorfield 10 hours ago
(so, avoid side-effects in f)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
No file, test, or entry point is named. Start by determining whether this resolved discussion should become a Clojure example or documentation change; done would require a specified destination and acceptance criteria.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- clojure
- Domain
- developer-experience
- Issue type
- Documentation
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100