为什么我从此代码中收到错误?

时间:2016-09-13 17:37:27

标签: clojure

我是clojure的新手,正试图突破我一直遇到的一些墙壁。有问题的代码是函数v3,它应该接受4个参数:

  • 要使用的最小和最大整数mima 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)))

2 个答案:

答案 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;回到循环目标。否则它不会做太多。我添加了以下内容:

  1. a recur到循环。
  2. let语句已添加到loop向量(起始值)。
  3. {li> println语句在if语句的false子句中。
  4. 删除了检查计数的第一个if - 语句
  5. 将列表更改为矢量。在create code structures结构时(例如while writing macros),您可以在向量上使用列表。
  6. 请参阅:

    (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))))
  • 首先,我已将mima的顺序切换为符合 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

请注意,2tones都不会显示,但它们位于 (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;