为什么我从这段代码中得到一个错误?
我对clojure很陌生,正试图突破一些我不断遇到的问题。有问题的代码是函数v3
应接受4个参数:为什么我从这段代码中得到一个错误?
- 一分钟和一个最大整数,
mi
和ma
,与random-numbers
函数的使用在一定范围内找到号码, - 另一整数,
cnt
,以表示我多少个号码想在我的 最终名单,并 -
tones
,这是一个随机数字有 匹配一旦我计算一列整数模说号码12。
该函数应该运行,直到o
是包含也可在tones
列表随机数长度cnt
的列表。
我的文件汇编就好了,但是当我想用的东西来运行函数本身在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)))
首先,在同一行上输入括号,而不是在“Java”中输入更多的惯用Clojure。
当我调试代码,我看到它失败在调用m12
:random-numbers
返回序列和m12
调用mod
预计的数字。
可以通过例如从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
“重复”回到循环目标。否则它没有太大的作用。我添加了以下东西:
- a
recur
到循环。 - 将
let
声明添加到loop
载体(起始值)。 -
println
陈述在if
陈述的错误条款中。 - 删除第一个
if
-检查计数的陈述 - 将列表更改为向量。当您使用create code structures结构时(例如while writing macros),您可以在矢量上使用列表。
参见:
(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])
(注意,我改变了你15 cnt
4,改变了列表的向量)几次,你会得到例如以下的输出:
a not in tones, o: [4 4]
a not in tones, o: [9 5 5]
a not in tones, o: []
already 4 tones generated
a not in tones, o: [7]
希望这会有所帮助。
感谢您的建议,我会在下一次寻求帮助之前尝试突破我的Java习惯。如果您调试我的代码,您看到了什么?看起来你的评论可能已经过早地结束了。 编辑:没关系,我现在可以看到其余的,谢谢你的帮助。 – Sturla
我想我明白你在做什么。
这是自动构图练习。您的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
一样。
除了各种针对clojure语义的攻击(如@Erwin所述)之外,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
。这是因为音调范围52到58会映射到音调类别范围4到10.
现在让我们累积音调而不是音调类别。我们需要移动的转换测试中,替换...
(let [a (tone-class (random-number mi ma))]
(recur (if (tone-set a) (conj o a) o)))
...与...
(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
一个惯用的版本会使用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)))
这会首先产生序列前沿。虽然通过查看结果无法判断,但上述修复后的版本会将其重新置于前面。
另一种惯用的v3
使用->>
threading macro捕捉功能级联调用:
(defn v3 [mi ma cnt tones]
(->> (repeatedly #(random-number mi ma))
(filter (comp (set tones) tone-class))
(take cnt)))
很好完成。谢谢。 –
是不是这只是国防部需要一个号码,你给它一个序列? –
我想可能是这样,随机数函数可能会返回一个1的序列。我会尝试,谢谢:) – Sturla
这样的问题坐在[CodeReview](http://codereview.stackexchange.com/)比在Stackoverflow更好。 – Thumbnail