我是clojure的新手,正试图突破我一直遇到的一些墙壁。有问题的代码是函数v3
,它应该接受4个参数:
mi
和ma
random-numbers
用于查找特定范围内的数字,cnt
,表示我想要的数字
最终名单,tones
,这是随机数具有的整数列表
一旦我计算出所述数字的模12,就匹配。该函数应该运行,直到o
是一个长度为cnt
的列表,其中包含同样位于tones
列表中的随机数。
我的文档编译得很好,但是当我想在repl中运行函数时,例如使用类似(v3 58 52 15 '(0 2 4 5 7 9))
之类的东西,我收到以下错误:
ClassCastException clojure.langLazySeq cannot be cast to java.lang.Number clojure.langNumbers.reminder (Numbers.java:173)
这是我的代码
(defn random-numbers [start end n]
(repeatedly n #(+ (rand-int (- end start)) start)))
(defn m12 [input]
(mod input 12))
(defn in? [coll elm]
(some #(= elm %) coll))
(defn v3 [ma mi cnt tones]
(let [o '()]
(loop []
(when(< (count o) cnt)
(let [a (m12 (random-numbers mi ma 1))]
(if (in? tones a)
(conj o a)))))
(println o)))
答案 0 :(得分:3)
首先,在同一行上键入括号是更惯用的Clojure,而不是在&#34; Java&#34; -way中。
当我调试代码时,我看到它在调用m12
时失败:random-numbers
返回一个序列,mod
中对m12
的调用需要一个数字。< / p>
您可以通过从random-numbers
返回的序列中获取第一个元素来解决此问题:
(defn v3
[ma mi cnt tones]
(let [o '()]
(loop []
(when (< (count o) cnt)
(let [a (m12 (first (random-numbers mi ma 1)))]
(if (in? tones a)
(conj o a)))))
(println o)))
/编辑
我不确定你的代码应该做什么,但这并没有阻止我做一些更改。如果您使用loop
,通常也会看到recur
到&#34;重复&#34;回到循环目标。否则它不会做太多。我添加了以下内容:
recur
到循环。let
语句已添加到loop
向量(起始值)。println
语句在if
语句的false子句中。
if
- 语句请参阅:
(defn v3
[ma mi cnt tones]
(loop [o []]
(if (< (count o) cnt)
(let [a (m12 (first (random-numbers mi ma 1)))]
(if (in? tones a)
(recur (conj o a))
(println "a not in tones, o:" o)))
(println "already " cnt "tones generated"))))
如果您运行(v3 58 52 4 [0 2 4 5 7 9])
(请注意我将cnt
的15更改为4并将列表更改为向量),您会得到以下输出:
a not in tones,o:[4 4]
a不是音调,o:[9 5 5]
a不是音调,o:[]
已经产生了4个音调 a不是音调,o:[7]
希望这有帮助。
答案 1 :(得分:1)
我想我明白你要做什么了。
这是自动组合练习。您的v3
函数旨在生成一系列音
mi
n和ma
x给出的范围内。 tones
)中抽取音调等级 m12
函数返回音调的音调类别,所以我们称之为:
(defn tone-class [tone]
(mod tone 12))
虽然我们关于它,但我认为如果我们添加相反的数字,您的random-number
函数会更容易阅读:
(defn random-number [start end]
(+ start (rand-int (- end start))))
请注意,可能的值包括start
但不包括end
,就像the standard range
一样。
除@Erwin所描述的针对clojure语义的各种攻击外,v3
下的算法存在问题。如果我们要修复它(我们会),它会产生一系列音调类,而不是音调。解释为音调,这些音调不会超出基本八度音程,无论指定的音调范围是多大。
已修复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))))
mi
和ma
的顺序切换为符合
range
等。tones
转换为一个集合,因此可以作为一个集合
会员功能。 o
足够大。 在循环内,如果候选o
不合适,我们会重复a
,但如果匹配则(conj o a)
。(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)
我们来试试吧!
0
请注意,2
和tones
都不会显示,但它们位于 (let [a (tone-class (random-number mi ma))]
(recur (if (tone-set a) (conj o a) o)))
中。这是因为音调范围52到58映射到音调等级范围4到10。
现在让我们积累音调而不是音调类别。我们需要在测试中移动转换,替换...
(let [a (random-number mi ma)]
(recur (if (tone-set (tone-class a)) (conj o a) o)))
...与......
(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)
这给了我们,例如,
v3
惯用语(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)))
惯用版将使用the sequence library:
v3
这首先生成序列前端。虽然您无法通过查看结果来判断,但上面修复的版本会将其重新生成。
替代惯用语(defn v3 [mi ma cnt tones]
(->> (repeatedly #(random-number mi ma))
(filter (comp (set tones) tone-class))
(take cnt)))
使用->>
threading macro捕获级联函数调用:
select 1 where NULL <> -1;