I think I see what you are trying to do.
This is an exercise in automatic composition. Your v3
function is intended to generate a sequence of tones
- in a range given by
mi
n and ma
x.
- with tone class drawn from a given set of tone classes (
tones
)
The m12
function returns the tone class of a tone, so let's call it that:
(defn tone-class [tone]
(mod tone 12))
While we're about it, I think your random-number
function is easier to read if we add the numbers the other way round:
(defn random-number [start end]
(+ start (rand-int (- end start))))
Notice that the possible values include start
but not end
, just as the standard range
does.
Apart from your various offences against clojure semantics, as described by @Erwin, there is a problem with the algorithm underlying v3
. Were we to repair it (we will), it would generate a sequence of tone classes, not tones. Interpreted as tones, these do not move beyond the base octave, however wide the specified tone range.
A repaired v3
(defn v3 [mi ma cnt tones]
(let [tone-set (set tones)]
(loop [o '()]
(if (< (count o) cnt)
(let [a (tone-class (random-number mi ma))]
(recur (if (tone-set a) (conj o a) o)))
o))))
- For a start, I've switched the order of
mi
and ma
to conform with
range
and the like.
- We turn
tones
into a set, which therefore works as a
membership function.
- Then we loop until the resulting sequence,
o
, is big enough.
- We return the result rather than print it.
Within the loop, we recur on the same o
if the candidate a
doesn't fit, but on (conj o a)
if it does. Let's try it!
(v3 52 58 15 '(0 2 4 5 7 9))
;(4 5 9 7 7 5 7 7 9 7 5 7 4 9 7)
Notice that neither 0
nor 2
appears, though they are in tones
. That's because the tone range 52 to 58 maps into tone class range 4 to 10.
Now let's accumulate tones instead of tone classes. We need to move conversion inside the test, replacing ...
(let [a (tone-class (random-number mi ma))]
(recur (if (tone-set a) (conj o a) o)))
... with ...
(let [a (random-number mi ma)]
(recur (if (tone-set (tone-class a)) (conj o a) o)))
This gives us, for example,
(v3 52 58 15 '(0 2 4 5 7 9))
;(53 52 52 52 55 55 55 53 52 55 53 57 52 53 57)
An idiomatic v3
An idiomatic version would use the sequence library:
(defn v3 [mi ma cnt tones]
(let [tone-set (set tones)
numbers (repeatedly #(random-number mi ma))
in-tones (filter (comp tone-set tone-class) numbers)]
(take cnt in-tones)))
This generates the sequence front first. Though you can't tell by looking at the outcome, the repaired version above generates it back to front.
An alternative idiomatic v3
Using the ->>
threading macro to capture the cascade of function calls:
(defn v3 [mi ma cnt tones]
(->> (repeatedly #(random-number mi ma))
(filter (comp (set tones) tone-class))
(take cnt)))