2024 年 Clojure 状态调查! 中分享您的想法。

欢迎!请在 关于 页面查看更多关于如何使用此功能的信息。

0
core.rrb-vector
我遇到了一些奇怪的行为,但我无法找到一个小失败的例子。


(defn quicksort [v]
  (if (<= (count v) 1)
    v
    (let [[x & xs] v]
      (rrb/catvec (quicksort (filterv #(<= % x) xs))
                  [x]
                  (quicksort (filterv #(> % x) xs))))))


我们可以用 test.check 检查此实现。


(defn ascending? [coll]
  (every? (fn [[a b]] (<= a b))
          (partition 2 1 coll)))

(def property
  (prop/for-all [v (gen/vector gen/int)]
    (let [s (quicksort v)]
      (and (= (count v) (count s))
          (ascending? s)))))

(tc/quick-check 10000 property)

;; => {:result true, :num-tests 10000, :seed 1440948212354}


尽管我将检查次数增加到 1e6,但 test.check 仍无法找到失败的案例。

然而,由于某种原因,我在一个包含 1193 个元素的向量上获得了 “类型转换异常:clojure.lang.PersistentVector$Node 无法转换为 [I”。

{}
(quicksort (read-string (slurp "failing-1193.edn")))
{}

5 答案

0
_由 jonase 添加的评论

表达式


(quicksort (shuffle (range 1e6)))


1. 成功 (~20%)
2. 抛出 ArrayIndexOutOfBoundsException (~20%)


#error {
 :cause "33"
 :via
 [{:type java.lang.ArrayIndexOutOfBoundsException
   :message "33"
   :at [clojure.core.rrb_vector.rrbt.Vector$fn__3827 invoke "rrbt.clj" 621]}]
 :trace
 [[clojure.core.rrb_vector.rrbt.Vector$fn__3827 invoke "rrbt.clj" 621]
  [clojure.core.rrb_vector.rrbt.Vector arrayFor "rrbt.clj" 620]
  [clojure.core.rrb_vector.rrbt.VecSeq chunkedNext "rrbt.clj" 111]
  [clojure.core.rrb_vector.rrbt.VecSeq next "rrbt.clj" 74]
  [clojure.lang.RT next "RT.java" 674]
  [clojure.core$next__4112 invoke "core.clj" 64]
  [clojure.core$nthnext invoke "core.clj" 3038]
  [clojure.core$print_sequential 调用 "core_print.clj" 49]
  [clojure.core$fn__5859 调用 "core_print.clj" 206]
  [clojure.lang.MultiFn 调用 "MultiFn.java" 233]
  [clojure.tools.nrepl.middleware.pr_values$pr_values$fn$reify__600 发送 "pr_values.clj" 35]
  [sun.reflect.GeneratedMethodAccessor13 调用 nil -1]
  [sun.reflect.DelegatingMethodAccessorImpl 调用 "DelegatingMethodAccessorImpl.java" 43]
  [java.lang.reflect.Method 调用 "Method.java" 606]
  [clojure.lang.Reflector 调用MatchingMethod "Reflector.java" 93]
  [clojure.lang.Reflector 调用InstanceMethod "Reflector.java" 28]
  [clojure.tools.nrepl.middleware.load_file$wrap_load_file$fn$reify__787 发送 "load_file.clj" 93]
  [clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__623$fn__634 调用 "interruptible_eval.clj" 82]
  [clojure.main$repl$read_eval_print__7099 调用 "main.clj" 241]
  [clojure.main$repl$fn__7108 调用 "main.clj" 258]
  [clojure.main$repl doInvoke "main.clj" 258]
  [clojure.lang.RestFn 调用 "RestFn.java" 1523]
  [clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__623 调用 "interruptible_eval.clj" 58]
  [clojure.lang.AFn 应用 "AFn.java" 152]
  [clojure.lang.AFn 应用 "AFn.java" 144]
  [clojure.core$apply 调用 "core.clj" 630]
  [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1868]
  [clojure.lang.RestFn 调用 "RestFn.java" 425]
  [clojure.tools.nrepl.middleware.interruptible_eval$evaluate 调用 "interruptible_eval.clj" 56]
  [clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__665$fn__668 调用 "interruptible_eval.clj" 191]
  [clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__660 调用 "interruptible_eval.clj" 159]
  [clojure.lang.AFn 运行 "AFn.java" 22]
  [java.util.concurrent.ThreadPoolExecutor 运行worker "ThreadPoolExecutor.java" 1145]
  [java.util.concurrent.ThreadPoolExecutor$Worker 运行 "ThreadPoolExecutor.java" 615]
  [java.lang.Thread 运行 "Thread.java" 745]]}


3. 抛出上述提到的 ClassCastException (~60%)


#error {
 :原因 "clojure.lang.PersistentVector$Node 无法转换到 [I"
 :via
 [{:类型 clojure.lang.Compiler$CompilerException
   :消息 "java.lang.ClassCastException: clojure.lang.PersistentVector$Node cannot be cast to [I, compiling:(/Users/jonasenlund/dev/clojure/the-other-datastructures/src/the_other_datastructures/rrb.clj:221:1)"
   :at [clojure.lang.Compiler load "Compiler.java" 7239]}
  {:类型 java.lang.ClassCastException
   :消息 "clojure.lang.PersistentVector$Node cannot be cast to [I"
   :at [clojure.lang.Numbers ints "Numbers.java" 1396]}]
 :trace
 [[clojure.lang.Numbers ints "Numbers.java" 1396]
  [clojure.core.rrb_vector.nodes$fold_tail 调用 "nodes.clj" 265]
  [clojure.core.rrb_vector.nodes$fold_tail 调用 "nodes.clj" 268]
  [clojure.core.rrb_vector.rrbt$splice_rrbts 调用 "rrbt.clj" 1357]
  [clojure.core.rrb_vector.rrbt.Vector splicev "rrbt.clj" 928]
  [clojure.core.rrb_vector$catvec 调用 "rrb_vector.clj" 54]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 217]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 217]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 217]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 219]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 217]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 219]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 219]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 217]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 217]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 217]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 219]
  [the_other_datastructures.rrb$eval4682$quicksort__4683 调用 "rrb.clj" 217]
  [the_other_datastructures.rrb$eval4921 调用 "rrb.clj" 221]
  [clojure.lang.Compiler eval "Compiler.java" 6782]
  [clojure.lang.Compiler load "Compiler.java" 7227]
  [user$eval4909 调用 "form-init3543508351311666483.clj" 1]
  [clojure.lang.Compiler eval "Compiler.java" 6782]
  [clojure.lang.Compiler eval "Compiler.java" 6745]
  [clojure.core$eval 调用 "core.clj" 3081]
  [clojure.main$repl$read_eval_print__7099$fn__7102 调用 "main.clj" 240]
  [clojure.main$repl$read_eval_print__7099 调用 "main.clj" 240]
  [clojure.main$repl$fn__7108 调用 "main.clj" 258]
  [clojure.main$repl doInvoke "main.clj" 258]
  [clojure.lang.RestFn 调用 "RestFn.java" 1523]
  [clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__623 调用 "interruptible_eval.clj" 58]
  [clojure.lang.AFn 应用 "AFn.java" 152]
  [clojure.lang.AFn 应用 "AFn.java" 144]
  [clojure.core$apply 调用 "core.clj" 630]
  [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1868]
  [clojure.lang.RestFn 调用 "RestFn.java" 425]
  [clojure.tools.nrepl.middleware.interruptible_eval$evaluate 调用 "interruptible_eval.clj" 56]
  [clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__665$fn__668 调用 "interruptible_eval.clj" 191]
  [clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__660 调用 "interruptible_eval.clj" 159]
  [clojure.lang.AFn 运行 "AFn.java" 22]
  [java.util.concurrent.ThreadPoolExecutor 运行worker "ThreadPoolExecutor.java" 1145]
  [java.util.concurrent.ThreadPoolExecutor$Worker 运行 "ThreadPoolExecutor.java" 615]
  [java.lang.Thread 运行 "Thread.java" 745]]}
0
_由 jonase 添加的评论

我不确定这与问题是否相关,但以下表达式抛出 NPE(将 rrb/catvec 更改为 clojure.core/into 得到预期结果 [])


(nth (iterate pop (nth (iterate #(rrb/catvec [0] %) []) 963)) 963)



#error {
 :原因 nil
 :via
 [{:类型 clojure.lang.Compiler$CompilerException
   :消息 "java.lang.NullPointerException, 编译位置:(("/Users/jonasenlund/dev/clojure/the-other-datastructures/src/the-other-datastructures/rrb.clj":201:5"))
   :at [clojure.lang.Compiler load "Compiler.java" 7239]}
  {:type java.lang.NullPointerException}
   :message nil
   :at [clojure.core.rrb_vector.nodes$reify__3483 正常 "nodes.clj" 46]}]
 :trace
 [[clojure.core.rrb_vector.nodes$reify__3483 正常 "nodes.clj" 46]
  [clojure.core.rrb_vector.rrbt.Vector popTail "rrbt.clj" 686]
  [clojure.core.rrb_vector.rrbt.Vector popTail "rrbt.clj" 727]
  [clojure.core.rrb_vector.rrbt.Vector pop "rrbt.clj" 487]
  [clojure.lang.RT pop "RT.java" 716]
  [clojure.core$pop 调用 "core.clj" 1409]
  [clojure.lang.Iterate first "Iterate.java" 47]
  [clojure.lang.Iterate next "Iterate.java" 54]
  [clojure.lang.RT nthFrom "RT.java" 867]
  [clojure.lang.RT nth "RT.java" 840]
  [the_other_datastructures.rrb$eval7254 调用 "rrb.clj" 201]
  [clojure.lang.Compiler eval "Compiler.java" 6782]
  [clojure.lang.Compiler load "Compiler.java" 7227]
  [user$eval7241 调用 "form-init121723447646604580.clj" 1]
  [clojure.lang.Compiler eval "Compiler.java" 6782]
  [clojure.lang.Compiler eval "Compiler.java" 6745]
  [clojure.core$eval 调用 "core.clj" 3081]
  [clojure.main$repl$read_eval_print__7099$fn__7102 调用 "main.clj" 240]
  [clojure.main$repl$read_eval_print__7099 调用 "main.clj" 240]
  [clojure.main$repl$fn__7108 调用 "main.clj" 258]
  [clojure.main$repl doInvoke "main.clj" 258]
  [clojure.lang.RestFn 调用 "RestFn.java" 1523]
  [clojure.tools.nrepl.middleware.interruptible_eval$evaluate$fn__623 调用 "interruptible_eval.clj" 58]
  [clojure.lang.AFn 应用 "AFn.java" 152]
  [clojure.lang.AFn 应用 "AFn.java" 144]
  [clojure.core$apply 调用 "core.clj" 630]
  [clojure.core$with_bindings_STAR_ doInvoke "core.clj" 1868]
  [clojure.lang.RestFn 调用 "RestFn.java" 425]
  [clojure.tools.nrepl.middleware.interruptible_eval$evaluate 调用 "interruptible_eval.clj" 56]
  [clojure.tools.nrepl.middleware.interruptible_eval$interruptible_eval$fn__665$fn__668 调用 "interruptible_eval.clj" 191]
  [clojure.tools.nrepl.middleware.interruptible_eval$run_next$fn__660 调用 "interruptible_eval.clj" 159]
  [clojure.lang.AFn 运行 "AFn.java" 22]
  [java.util.concurrent.ThreadPoolExecutor 运行worker "ThreadPoolExecutor.java" 1145]
  [java.util.concurrent.ThreadPoolExecutor$Worker 运行 "ThreadPoolExecutor.java" 615]
  [java.lang.Thread 运行 "Thread.java" 745]]}
0
_评论由: michalmarczyk_ 发表

再次感谢错误报告,并对后续.response表示深深的感谢!您是否愿意将这些测试用例封装进补丁中?

关于修复方案——我可以看到原始问题案例中发生的大致情况,剩下的就是追踪确切的计算错误发生的位置……一旦排序完成,我将发布一个新版本。
0

评论由: jonase 发表

我添加了ClassCastException和NullPointerException失败的测试用例。奇怪的是,我只能在repl中复现ArrayIndexOutOfBoundsException。

0
参考:https://clojure.atlassian.net/browse/CRRBV-12(由jonase报告)
...