Unexplained behaviour in atom - clojure

I have an atom which stores current and historical event counts.
(def buckets (atom (list)))
It starts as 20 empty values.
(reset! buckets (apply list (repeat 20 0)))
=> (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
The head bucket gets incremented for each event.
(defn- inc-bucket [buckets]
(conj (rest buckets) (inc (first buckets))))
(defn event-happened [] (swap! buckets inc-bucket))
=> (event-happened)
(1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
It gets shifted once a second to give a history of counts.
(defn- shift-buckets [buckets]
(conj (drop-last buckets) 0))
(once-a-second-run (swap! buckets shift-bucket))
=> (swap! buckets shift-bucket)
(0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
This all works fine most of the time. But occasionally (say once a week) I find that the length of buckets has been reset to 5, not the correct value (20 in this example).
=> #buckets
(0 1 0 0 0)
The only place buckets is used is in these functions and with a deref to observe the value.
Something went wrong, and I can't work out how or where. The only place buckets is modified is during the two above swap!s and as I think they're being used correctly. Any ideas?

I found the answer. Laziness and unhandled exceptions in atoms. There is no magic.
user=> (reset! buckets (apply list (repeat 20 0)))
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
user=> (dotimes [_ 99999] (swap! buckets shift-buckets))
nil
user=> #buckets
StackOverflowError clojure.core/map/fn--4557 (core.clj:2627)
user=> (type #buckets)
clojure.lang.Cons
This had showed up in the log, but I hadn't seen it (there's a lot else going on). But here's the crazy thing:
user=> #buckets ; again
(0 0)
I don't know why it would give that value. It's not because a cons cell has a head and a tail, because in production that was (0 0 0 0 0). Either way it's undefined behaviour so there's no point guessing.
To fix it, the list must be realised each time.
user=> (defn- shift-buckets-nonlazy [buckets]
#_=> (apply list (conj (drop-last buckets) 0)))
#'user/shift-buckets-nonlazy
user=> (reset! buckets (apply list (repeat 20 0)))
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)
user=> (dotimes [_ 999999] (swap! buckets shift-buckets-nonlazy))
nil
user=> (type #buckets)
clojure.lang.PersistentList
user=> #buckets
(0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0)

The problem has to be in code you haven't posted: everything in your question looks perfectly correct, and can't cause the behavior you describe.

Related

List calling with car and cdr in scheme/lisp

Currently setting cells in list notation using scheme. My question is how to make scheme(Dr Racket) list pair correctly using cons. My code accounts for the right location I want but creates a list by adding on the front. I am currently only working on the column = 1, 2, 3 or 4 aspect of this, and when row = 1 ONLY... Any help would be greatly appreciated.
(define KMMgame 0)
(define (KMMStartGame)
( begin
(set! KMMgame '( 1(4 9 0 0)(99 0 0 0)(88 0 0 0)(11 0 0 1)
(3 8 0 0)(77 0 0 0)(66 0 0 0)(55 0 0 2)
(2 0 0 0)(44 0 0 0)(33 0 0 0)(22 0 0 3)
(1 0 0 0)(43 0 0 0)(34 0 0 0)(87 0 0 4)))
(display "Starting Game Now!" ) (newline)
#t))
;Passes list without the one on front (That is for my player state, irrelevant to my question)
(define ( KMMmove KMMgame Plane Row Column Token)
(KMMMove (car(cdr KMMgame)) (cdr (cdr KMMgame)) Plane Row Column Token) )
;Set the cell to token.
(define (KMMMove KMMgame KMMend Plane Row Column Token)
(if (= Row 1)
(if (= Column 1)
(cons (cons Token (cdr KMMgame)) KMMend)
(cons (car KMMgame) (KMMMove (cdr KMMgame) KMMend Plane Row (- Column 1) Token))
)
;Next line accounts for rows greater than one, not working yet so please disregard. Exists to compile.
(cons (cons (car(cdr (cdr KMMgame))) (KMMMove (car KMMgame) Plane (- Row 1) Column Token)) (cdr(cdr KMMgame))
)
)
)
(KMMMove KMMgame 4 1 1 999)
Plane 4, Row 1, Column 1, Token to be added instead of current number 999, will print the desired output but inside an extra set of parenthesis:
((999 9 0 0)
(99 0 0 0)
(88 0 0 0)
(11 0 0 1)
(3 8 0 0)
(77 0 0 0)
(66 0 0 0)
(55 0 0 2)
(2 0 0 0)
(44 0 0 0)
(33 0 0 0)
(22 0 0 3)
(1 0 0 0)
(43 0 0 0)
(34 0 0 0)
(87 0 0 4))
( KMMmove KMMgame 4 1 2 999)
Plane 4, Row 1, Column 2, Token 999, gives the correct location for column but is pairing the front of the list outside.
(4
(999 0 0)
(99 0 0 0)
(88 0 0 0)
(11 0 0 1)
(3 8 0 0)
(77 0 0 0)
(66 0 0 0)
(55 0 0 2)
(2 0 0 0)
(44 0 0 0)
(33 0 0 0)
(22 0 0 3)
(1 0 0 0)
(43 0 0 0)
(34 0 0 0)
(87 0 0 4))
Desired output for column 2:
(4 999 0 0)
(99 0 0 0)
(88 0 0 0)
(11 0 0 1)
(3 8 0 0)
(77 0 0 0)
(66 0 0 0)
(55 0 0 2)
(2 0 0 0)
(44 0 0 0)
(33 0 0 0)
(22 0 0 3)
(1 0 0 0)
(43 0 0 0)
(34 0 0 0)
(87 0 0 4)
To get a list like that, I'd suggest helper functions!
(define (newGameState KMMgame Row Column Plane Token)
(if (= Plane 4)
(steptwo KMMgame Row Column Plane Token)
(newGameState KMMgame (+ 4 Row) (+ Plane 1) Column Token)
)
)
(define (steptwo KMMgame Row Column Plane Token)
(if (= Row 1)
(cons (stepthree (car (cdr KMMgame)) Row Column Plane Token) (cdr (cdr KMMgame)))
(cons (car (cdr KMMgame))(steptwo (cdr KMMgame) (- Row 1) Column Plane Token))
)
)
(define (stepthree KMMgame Row Column Plane Token)
(if (= Column 1)
(cons Token (cdr KMMgame))
(cons (car KMMgame) (stepthree (cdr KMMgame) Row (- Column 1) Plane Token))
)
)
This should give desired output!

how to split a vector on a delimiter

I have a vector that contains numbers.
The structure of the vector is the following:
items of arbitrary length
a separator [0 0 0 0 0] (0 repeated 5 times) between the items
I want to write a function split that retrieves the list of the items (without the separator): It is similar to string/split.
For instance:
(split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 199])
; => [[123 0 1] [1 1] [1 0 1] [0 0 1 199]]
Remark: the code has to be effective as the length of the vector is around 1 million.
Thanks for your help.
Here:
(defn the-split [coll]
(let [part (partition-by identity coll)
ppart (partition-by #(= [0 0 0 0 0] %) part)
almost (map #(apply concat %) ppart)]
(filter (partial not= [0 0 0 0 0]) almost)))
(the-split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
=> ((123 0 1) (1 1) (1 0 1) (1 199))
Here's one approach -- with the [0 0 0 0 0] separator hardwired, but straightforward to generalize:
(defn split5z [xs]
(let [delim [0 0 0 0 0]
step (fn step [xs seg]
(lazy-seq
(if-let [xs (seq xs)]
(let [window (take 5 xs)]
(if (= window delim)
(cons seg (step (drop 5 xs) []))
(step (rest xs) (conj seg (first xs)))))
(list seg))))]
(step xs [])))
Applying it to your sample input:
(split5z [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
;= ([123 0 1] [1 1] [1 0 1] [1 199])
Wrap in vec if you'd like the output to be a vector rather than a seq of vectors.
Another approach -- this time eagerly consuming the input with loop/recur:
(defn split5z [sep xs]
(let [scnt (count sep)]
(loop [xs (seq xs)
out []
seg []]
(if xs
(if (= (take scnt xs) sep)
(recur (nthnext xs scnt)
(conj out seg)
[])
(recur (next xs)
out
(conj seg (first xs))))
(if (seq seg)
(conj out seg)
seg)))))
At the REPL:
(split5z [0 0 0 0 0]
[123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 1 199])
;= [[123 0 1] [1 1] [1 0 1] [1 199]]
A lazy solution:
(defn split [v]
(let [delim (repeat 5 0)
i (->> v (partition 5 1) (take-while #(not= delim %)) count)]
(if (zero? i) [v] (lazy-seq (cons (subvec v 0 i)
(split (subvec v (+ i 5))))))))
For example
(split [123 0 1 0 0 0 0 0 1 1 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 199])
; ([123 0 1] [1 1] [1 0 1] [0 0 1 199])

Using Clojure vector to model a 7 card poker hand

I have a vector that represents a 7 card poker hand and I want to find the next hand using the following method:
values are from 0 to 12 and are sorted (e.g. [0 0 7 11 11 12 12])
A valid vector has atmost 4 of one value
The first valid vector is [0 0 0 0 1 1 1]
If the values at index and index + 1 are different then increment the value at index and set all the values from 0 to index - 1 to zero
Repeat the last step until the vector is valid
For example, (next-hand [0 0 0 0 1 1 1]) would return [0 0 0 1 1 1 1] directly. However, (next-hand [0 0 0 1 1 1 1]) would loop through,
[0 0 1 1 1 1 1] (invalid)
[0 1 1 1 1 1 1] (invalid)
[1 1 1 1 1 1 1] (invalid)
[0 0 0 0 0 0 2] (invalid)
[0 0 0 0 0 1 2] (invalid)
and return this valid hand:
[0 0 0 0 1 1 2]
Here is the sudo code I have, but need to convert this to clojure. Note how I'm adding a really large integer to the end of the hand to make the last comparison always true. Thus, in the case of [1 1 1 1 1 1 1 99] the first loop would end at i=6 with 1 < 99 == true.
let hand = [hand 99]
while hand is invalid
for i in range(0,6)
if hand[i] < hand[i+1]
increment hand[i]
break
for j in range(0,i-1)
hand[j] = 0
Edit Friday, Mar 29, 2013:
In order for the select solution to work with the poker hand model I added an is-valid function like so:
(defn is-valid [v]
(let [distinct-ranks (partition-by identity v)
count-distinct (map count distinct-ranks)
max-count (apply max count-distinct)]
(<= max-count 4)))
and updated to (filter #(is-valid %) in next-hand.
One possible solution:
(defn next [v]
(let [i (->> (map < v (rest v))
(map-indexed vector)
(filter #(% 1))
first)
index (if i (i 0) 6)]
(for [[i x] (map-indexed vector v)]
(cond (= i index) (inc x)
(< i index) 0
:else x))))
(defn next-hand [v]
(->> (iterate next (next v))
(filter #(= 4 (apply + %)))
first
vec))
(next-hand [0 0 0 1 1 1 1])

How to count the number of ones in a vector, given an upper limit

Given a vector of ones and zeros, I would like to count the number of entries with a value one. However, the vector may be very long and I only care to know if the vector has zero, one, or more entries with a value o f one.
Using the approach given here, I can count the number of ones in the vector.
(count (filter #{1} [1 0 1 0 0 1 1]))
Can I limit filter (or use some other approach) to avoid visiting any more than three elements of the vector, in this case?
Filter is lazy, so will only do as much work as required. Since you only care about having no 1's, one 1's or two or more ones, you only need to examine up to two elements of the filtered sequence of 1's, so just take 2 before you count:
user=> (count (take 2 (filter #{1} [1 0 1 0 0 1 1])))
2
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 0])))
0
user=> (count (take 2 (filter #{1} [0 0 0 0 0 0 1])))
1
user=> (def rare (repeatedly #(if (< (rand) 0.0001) 1 0)))
#'user/rare
user=> (take 10 rare)
(0 0 0 0 0 0 0 0 0 0)
user=> (count (take 2 (filter #{1} rare)))
2

Clojure - displaying some output correctly

I'm quite new to clojure so still trying to learn... well a LOT of stuff. Right now I'm stuck on trying to get some output to display properly. Here is my function:
;function 7 - display the board
(defn display [small medium large]
(let [board (loop [i 0 boardVector [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]]
;(prn (bit-test small i)(bit-test medium i)(bit-test large i))
(if (< i 16)
(cond
;nothing exists
(and (not(bit-test small i))(not(bit-test medium i))(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 0)))
;only small bit exists
(and (bit-test small i)(not(bit-test medium i))(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 1)))
;small and medium exists on square
(and (bit-test small i)(bit-test medium i)(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 3)))
;only medium exists on square
(and (not(bit-test small i))(bit-test medium i)(not(bit-test large i)))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 2)))
;medium and large exists on square
(and (not(bit-test small i))(bit-test medium i)(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 6)))
;only large exists on square
(and (not(bit-test small i))(not(bit-test medium i))(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 4)))
;all three exists on square
(and (bit-test small i)(bit-test medium i)(bit-test large i))
(recur (+ i 1) (assoc boardVector i (+ (nth boardVector i) 7)))
)
boardVector)
)
]
(prn board)
)
)
Here is what I'm using to pass as arguments:
(display 2r1001000100 2r101001000 2r111000000)
This function takes bit variables (that are no more than 16 in length...), and calculates a final vector depending on which bits are set. a small is worth 1, medium worth 2, large worth 4. This is why I have that condition statement outlining each different possibility, excluding the possibility of having a small and large, and no medium set at the same time.
Anyhow, if none of that makes sense, here's the actual question:
How do I get my current output that displays as:
[0 0 1 2 0 0 7 4 6 1 0 0 0 0 0 0]
nil
To make it display like this?
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
I've tried using functions such as apply, map, str, interpose... but I never could figure out what the heck I was doing wrong with them. Currently I have the output displayed as a side-effect (i think that is the correct name for that...), but it's always returning nil from the output of the prn function. Dunno how to get rid of that either. Would appreciate any help!
partition it into groups of 4, then print each group:
(dorun (map #(apply println %) (partition-all 4 r)))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
or using a for expression:
(dorun (for [line (partition-all 4 r)] (apply println line)))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
or using a doseq:
(doseq [line (partition-all 4 r)] (apply println line))
0 0 1 2
0 0 7 4
6 1 0 0
0 0 0 0
dorun (or doall) is required for the for and map examples because these are lazy and would otherwise not actually print anything unless the sequence they return was consumed. Calling apply with println and the sequence causes println to get the contents of the sequence as arguments instead of the sequence it's self, which keeps it from printing extra parens.