Threadsafe pop in clojure? - clojure

I've found this code on http://www.learningclojure.com/2010/11/yet-another-way-to-write-factorial.html, but I don't understand if/how the pop-task is supposed to be threadsafe. Doesn't it allow to return twice the same head ?
(def to-do-list (atom '()))
(defn add-task![t] (swap! to-do-list #(cons t %)))
(defn pop-task![] (let [h (first #to-do-list)] (swap! to-do-list rest) h))
If so, is it possible to keep using atom and write the peek and swap! atomically, or is this a job for the ref mechanism ?

Or you drop to a lower level.
(def to-do-list (atom nil))
(defn add-task!
[t]
(swap! to-do-list conj t))
(defn pop-task!
[]
(let [[h & r :as l] #to-do-list]
(if (compare-and-set! to-do-list l r)
h
(recur))))

Yeah, that code isn't thread safe. You can make it thread-safe by taking advantage of the fact that swap! returns the new value of the atom, which implies you need to combine the queue with the "popped" value.
(def to-do-list
(atom {}))
(defn add-task!
[t]
(swap! to-do-list
(fn [tl]
{:queue (cons t (:queue tl))})))
(defn pop-task!
[]
(let [tl (swap! to-do-list
(fn [old]
{:val (first (:queue old))
:queue (rest (:queue old))}))]
(:val tl)))

Related

Railroad oriented programming in clojure

I saw a talk about railroad oriented programming (https://www.youtube.com/watch?v=fYo3LN9Vf_M), but i somehow do not get how to work this out, if i use reduce, because reduce has two or even three arguments.
How am i able to to put the following code like a railroad? I seems to me hard, because of reduce taking a function as an argument in addition to the game object.
(defn play-game-reduce []
(let [game-init
(->>
(io/initialize-cards-and-players)
(shuffle-and-share-cards myio/myshuffle)
(announce))
play-round
(reduce play-card (assoc-in game-init [:current-trick] '()) [:p1 :p2 :p3 :p4])]
(reduce play-round game-init (range (get game-init :round-count)))))
The whole code is here:
https://github.com/davidh38/doppelkopf/blob/master/src/mymain.clj
The code should more look like this:
(->> (io/initialize-cards-and-players)
(shuffle-and-share-cards myio/myshuffle)
(announce)
reduce (play-round .. )
reduce (play-card ...))
That would look to me much more explicit.
That video was made for a different language and you can't directly transfer these ideas to Clojure.
I looked at your source code and there are some things to improve:
(defn play-card-inp []
(eval (read-string (read-line))))
You shouldn't use eval in production code.
Read-string is unsafe and you should use clojure.edn/read-string instead. I'm not sure what is expected input here and what is the result of the evaluation, maybe you should use just clojure.edn/read here.
(defn myshuffle [cards]
(shuffle cards)
)
(defn initialize-cards-and-players []
; init cards
(def cards '([0 :c], [1 :c],[2 :c], [3 :c], [0 :s], [1 :s], [2 :s], [3 :s]))
(def players '(:p1 :p2 :p3 :p4))
;(def round-players (take 4 (drop (who-won_trick tricks) (cycle (keys players)))))
; mix and share cards
{:players (zipmap players (repeat {:cards () :tricks ()}))
:current-trick ()
:round-start-player :p1
:cards cards
:round-count (/ (count cards) (count players))
:mode ""
})
You should delete myshuffle and use directly shuffle where needed. Ending parenthesis shouldn't be on a separate line.
Don't use def (creates global variable) inside defn, use let (creates local variables). I would rewrite this as:
(defn new-deck []
(for [letter [:c :s]
number (range 4)]
[number letter]))
(defn new-game []
(let [cards (new-deck)
players [:p1 :p2 :p3 :p4]]
{:players (zipmap players (repeat {:cards () :tricks ()}))
:current-trick ()
:round-start-player :p1
:cards cards
:round-count (/ (count cards) (count players))
:mode ""}))
Notes for mymain.clj:
(defn who-won-trick [trick]
(eval (read-string (read-line))))
Some unused function, same problems as above.
(defn share-card-to-player [game players-cards]
(assoc game
:players
(assoc
(get game :players)
(first players-cards)
(assoc (get (game :players) (first players-cards))
:cards
(second players-cards)))))
Use assoc-in and some destructuring, something like this:
(defn share-card-to-player [game [player cards]]
(assoc-in game [:players player :cards] cards))
Your next function:
(defn shuffle-and-share-cards [myshuffle game]
(reduce share-card-to-player game
(map vector
(keys (get game :players))
(->> (get game :cards)
(myshuffle)
(partition (/ (count (get game :cards))
(count (get game :players))))))))
You can also destructure hash-maps, so I would rewrite this as:
(defn shuffle-and-share-cards [{:keys [players cards] :as game}]
(let [card-piles (->> cards
shuffle
(partition (/ (count cards)
(count players))))]
(reduce share-card-to-player game
(map vector
(keys players)
card-piles))))
Next functions:
(defn announce [game]
game)
(defn play-card [game curr-player]
(println curr-player)
(println game)
(let [played-card (io/play-card-inp)]
(->
(assoc-in game [:players curr-player :cards]
(remove #(= played-card %) (get-in game [:players curr-player :cards])))
(assoc-in [:current-trick]
(conj (game [:current-trick]) played-card)))))
announce is useless and update and update-in are better here:
(defn play-card [game curr-player]
(println curr-player)
(println game)
(let [played-card (io/play-card-inp)]
(-> game
(update-in [:players curr-player :cards] #(remove #{played-card} %))
(update :current-trick conj played-card))))
And finally, the last two functions:
(defn play-game-reduce []
(let [game-init
(->>
(io/initialize-cards-and-players)
(shuffle-and-share-cards myio/myshuffle)
(announce))
play-round
(reduce play-card (assoc-in game-init [:current-trick] '()) [:p1 :p2 :p3 :p4])]
(reduce play-round game-init (range (get game-init :round-count)))))
(defn play-game []
(let [game-init
(->>
(io/initialize-cards-and-players)
(shuffle-and-share-cards io/myshuffle)
(announce))]
(loop [round 1 game game-init]
(let [game-next (loop [curr-player 1 game-next game]
(if (> curr-player 4)
game-next
(recur (inc curr-player)
(play-card game-next (keyword (str "p" curr-player))))))]
(if (> round 2)
game-next
(recur (inc round) game-next))))))
loop/recur will be probably more readable, but two reduce should also work:
(defn play-game-reduce []
(let [game-init (-> (io/new-game)
shuffle-and-share-cards)]
(reduce (fn [game round]
(reduce play-card (assoc-in game [:current-trick] '()) [:p1 :p2 :p3 :p4]))
game-init
(range (get game-init :round-count)))))
(play-game-reduce)
Version with one reduce:
(defn play-game-reduce []
(let [game-init (-> (io/new-game)
shuffle-and-share-cards)
turns (for [round (range (:round-count game-init))
player [:p1 :p2 :p3 :p4]]
[round player])]
(reduce (fn [game [round player]]
(let [state (cond-> game
(= player (:round-start-player game)) (assoc-in [:current-trick] '()))]
(play-card state player)))
game-init
turns)))
And I also noticed that there's no validation of whether the current player can really play inserted card.
OK, I watched the talk (for the record, it gives a 5 minute overview of FP, then discusses error handling in pipelines in F#.
I didn't really care for the content of the video.
Clojure uses Exceptions for error handling, so a Clojure function always has only one output. Therefore the whole bind and map thing in the video doesn't apply.
I haven't looked at F# much before, but after watching that video I think it over-complicates things without much benefit.

Checking odd parity in clojure

I have the following functions that check for odd parity in sequence
(defn countOf[a-seq elem]
(loop [number 0 currentSeq a-seq]
(cond (empty? currentSeq) number
(= (first currentSeq) elem) (recur (inc number) (rest currentSeq))
:else (recur number (rest currentSeq))
)
)
)
(defn filteredSeq[a-seq elemToRemove]
(remove (set (vector (first a-seq))) a-seq)
)
(defn parity [a-seq]
(loop [resultset [] currentSeq a-seq]
(cond (empty? currentSeq) (set resultset)
(odd? (countOf currentSeq (first currentSeq))) (recur (concat resultset (vector(first currentSeq))) (filteredSeq currentSeq (first currentSeq)))
:else (recur resultset (filteredSeq currentSeq (first currentSeq)))
)
)
)
for example (parity [1 1 1 2 2 3]) -> (1 3) that is it picks odd number of elements from a sequence.
Is there a better way to achieve this?
How can this be done with reduce function of clojure
First, I decided to make more idiomatic versions of your code, so I could really see what it was doing:
;; idiomatic naming
;; no need to rewrite count and filter for this code
;; putting item and collection in idiomatic argument order
(defn count-of [elem a-seq]
(count (filter #(= elem %) a-seq)))
;; idiomatic naming
;; putting item and collection in idiomatic argument order
;; actually used the elem-to-remove argument
(defn filtered-seq [elem-to-remove a-seq]
(remove #(= elem-to-remove %) a-seq))
;; idiomatic naming
;; if you want a set, use a set from the beginning
;; destructuring rather than repeated usage of first
;; use rest to recur when the first item is guaranteed to be dropped
(defn idiomatic-parity [a-seq]
(loop [result-set #{}
[elem & others :as current-seq] a-seq]
(cond (empty? current-seq)
result-set
(odd? (count-of elem current-seq))
(recur (conj result-set elem) (filtered-seq elem others))
:else
(recur result-set (filtered-seq elem others)))))
Next, as requested, a version that uses reduce to accumulate the result:
;; mapcat allows us to return 0 or more results for each input
(defn reducing-parity [a-seq]
(set
(mapcat
(fn [[k v]]
(when (odd? v) [k]))
(reduce (fn [result item]
(update-in result [item] (fnil inc 0)))
{}
a-seq))))
But, reading over this, I notice that the reduce is just frequencies, a built in clojure function. And my mapcat was really just a hand-rolled keep, another built in.
(defn most-idiomatic-parity [a-seq]
(set
(keep
(fn [[k v]]
(when (odd? v) k))
(frequencies a-seq))))
In Clojure we can refine our code, and as we recognize places where our logic replicates the built in functionality, we can simplify the code and make it more clear. Also, there is a good chance the built in is better optimized than our own work-alikes.
Is there a better way to achieve this?
(defn parity [coll]
(->> coll
frequencies
(filter (fn [[_ v]] (odd? v)))
(map first)
set))
For example,
(parity [1 1 1 2 1 2 1 3])
;#{1 3}
How can this be done with reduce function of clojure.
We can use reduce to rewrite frequencies:
(defn frequencies [coll]
(reduce
(fn [acc x] (assoc acc x (inc (get acc x 0))))
{}
coll))
... and again to implement parity in terms of it:
(defn parity [coll]
(let [freqs (frequencies coll)]
(reduce (fn [s [k v]] (if (odd? v) (conj s k) s)) #{} freqs)))

Grouping words and more

I'm working on a project to learn Clojure in practice. I'm doing well, but sometimes I get stuck. This time I need to transform sequence of the form:
[":keyword0" "word0" "word1" ":keyword1" "word2" "word3"]
into:
[[:keyword0 "word0" "word1"] [:keyword1 "word2" "word3"]]
I'm trying for at least two hours, but I know not so many Clojure functions to compose something useful to solve the problem in functional manner.
I think that this transformation should include some partition, here is my attempt:
(partition-by (fn [x] (.startsWith x ":")) *1)
But the result looks like this:
((":keyword0") ("word1" "word2") (":keyword1") ("word3" "word4"))
Now I should group it again... I doubt that I'm doing right things here... Also, I need to convert strings (only those that begin with :) into keywords. I think this combination should work:
(keyword (subs ":keyword0" 1))
How to write a function which performs the transformation in most idiomatic way?
Here is a high performance version, using reduce
(reduce (fn [acc next]
(if (.startsWith next ":")
(conj acc [(-> next (subs 1) keyword)])
(conj (pop acc) (conj (peek acc)
next))))
[] data)
Alternatively, you could extend your code like this
(->> data
(partition-by #(.startsWith % ":"))
(partition 2)
(map (fn [[[kw-str] strs]]
(cons (-> kw-str
(subs 1)
keyword)
strs))))
what about that:
(defn group-that [ arg ]
(if (not-empty arg)
(loop [list arg, acc [], result []]
(if (not-empty list)
(if (.startsWith (first list) ":")
(if (not-empty acc)
(recur (rest list) (vector (first list)) (conj result acc))
(recur (rest list) (vector (first list)) result))
(recur (rest list) (conj acc (first list)) result))
(conj result acc)
))))
Just 1x iteration over the Seq and without any need of macros.
Since the question is already here... This is my best effort:
(def data [":keyword0" "word0" "word1" ":keyword1" "word2" "word3"])
(->> data
(partition-by (fn [x] (.startsWith x ":")))
(partition 2)
(map (fn [[[k] w]] (apply conj [(keyword (subs k 1))] w))))
I'm still looking for a better solution or criticism of this one.
First, let's construct a function that breaks vector v into sub-vectors, the breaks occurring everywhere property pred holds.
(defn breakv-by [pred v]
(let [break-points (filter identity (map-indexed (fn [n x] (when (pred x) n)) v))
starts (cons 0 break-points)
finishes (concat break-points [(count v)])]
(mapv (partial subvec v) starts finishes)))
For our case, given
(def data [":keyword0" "word0" "word1" ":keyword1" "word2" "word3"])
then
(breakv-by #(= (first %) \:) data)
produces
[[] [":keyword0" "word0" "word1"] [":keyword1" "word2" "word3"]]
Notice that the initial sub-vector is different:
It has no element for which the predicate holds.
It can be of length zero.
All the others
start with their only element for which the predicate holds and
are at least of length 1.
So breakv-by behaves properly with data that
doesn't start with a breaking element or
has a succession of breaking elements.
For the purposes of the question, we need to muck about with what breakv-by produces somewhat:
(let [pieces (breakv-by #(= (first %) \:) data)]
(mapv
#(update-in % [0] (fn [s] (keyword (subs s 1))))
(rest pieces)))
;[[:keyword0 "word0" "word1"] [:keyword1 "word2" "word3"]]

Clojure multimethod dispatching on functions and values

I have a function that returns the indexes in seq s at which value v exists:
(defn indexes-of [v s]
(map first (filter #(= v (last %)) (zipmap (range) s))))
What I'd like to do is extend this to apply any arbitrary function for the existence test. My idea is to use a multimethod, but I'm not sure exactly how to detect a function. I want to do this:
(defmulti indexes-of ???)
(defmethod indexes-of ??? [v s] ;; v is a function
(map first (filter v (zipmap (range) s))))
(defmethod indexes-of ??? [v s] ;; v is not a function
(indexes-of #(= v %) s))
Is a multimethod the way to go here? If so, how can I accomplish what I'm trying to do?
If you want to use a multimethod it should be on the filter function, which is the one changing according to the existence test type.
So
(defmulti filter-test (fn [value element]
(cond
(fn? value) :function
:else :value)))
(defmethod filter-test :function
[value element]
(apply value [element]))
(defmethod filter-test :value
[value element]
(= value element))
(defn indexes-of [v s]
(map first (filter #(filter-test v (last %)) (zipmap (range) s))))
Consider the JVM doesn't support first-class functions, or lambdas, out of the box, so there's no "function" data type to dispatch on, that's the reason the fn? test.
None the less the predicate solution proposed by noisesmith is the proper way to go in this situation IMO.
(defmulti indexes-of (fn [v _]
(if (fn? v)
:function
:value)))
(defmethod indexes-of :function
[f coll]
(keep-indexed (fn [i v] (when (f v) i)) coll))
(defmethod indexes-of :value
[v coll]
(indexes-of (partial = v) coll))
How about something simpler and more general:
(defn index-matches [predicate s]
(map first (filter (comp predicate second) (map vector (range) s))))
user> (index-matches even? (reverse (range 10)))
(1 3 5 7 9)
user> (index-matches #{3} [0 1 2 3 1 3 44 3 1 3])
(3 5 7 9)
thanks to a suggestion from lgrapenthin, this function is also now effective for lazy input:
user> (take 1 (index-matches #{300000} (range)))
(300000)

Clojure local-variables

I want to create a function (thunk) that will return successive elements in a list. What is the best way to do this? I wrote this code based on an apparently flawed understanding of how local variables in clojure work:
(defn reader-for [commands]
(with-local-vars
[stream commands]
(fn []
(let
[r (var-get stream)]
(if (empty? r)
nil
(let
[cur (first r)
_ (var-set stream (rest r))]
cur))))))
In this code I get:
#<CompilerException java.lang.IllegalStateException: Var null/null is unbound. (Chapel.clj:1)>
which seems to suggest that with-local-vars is dynamically scoped. Is that true? Is there any lexically scoped alternative? Thanks for any help.
If you require mutable state, use one of the clojure reference types:
user=> (defn reader-for [coll]
(let [a (atom coll)]
(fn []
(let [x (first #a)]
(swap! a next)
x))))
#'user/reader-for
user=> (def f (reader-for [1 2 3]))
#'user/f
user=> (f)
1
user=> (f)
2
user=> (f)
3
user=> (f)
nil
Also, let is for lexical scoping, binding is for dynamic scoping.
Edit: the thread-safe version as pointed out by Alan.
(defn reader-for [coll]
(let [r (ref coll)]
#(dosync
(let [x (first #r)]
(alter r next)
x))))
And just for fun, a thread-safe version with atoms (don't do this):
(defn reader-for [coll]
(let [a (atom coll)]
(fn []
(let [ret (atom nil)]
(swap! a (fn [[x & xs]]
(compare-and-set! ret nil x)
xs))
#ret))))