这是一个 clojure.core.match 错误还是只有我一个?

Is this a clojure.core.match bug or it's just me?

(match
   [[1 2 3]]
   [(:or [_ _ 2] 
         [3 _ _])] :a0

   [(:or [_ _ 1] 
         [1 _ _])] :a1
   :else :else)

=> :else

在第一个片段中,我预计它会 return :a1

奇怪。

这个有效:

(match
   [[1 2 3]]
   [(:or [_ _ 2] 
         [1 _ _])] :a0

   [(:or [_ _ 1] 
         [3 _ _])] :a1
   :else :else)

=> :a0

这是预期的行为吗?

我会说这不是因为手册中从未提及您使用 :or 的方式。它应该用在这样的表达式中:

[4 (:or 5 6 7) _] :a1

所以你的代码应该看起来像

(match
         [[1 2 3]]
         [[_ _ 2]] :a0
         [[3 _ _]] :a0

         [[_ _ 1]] :a1
         [[1 _ _]] :a1
         :else :else)

但也许你应该咨询作者。很难说初衷是什么。

我认为这是 specialize-or-pattern-row 中的错误。我相信 groupable? 测试是错误的,因为在你的情况下,它对你的两个 OrPattern 是成功的,所以第二个 OrPattern 被第一个扩展替换(ps 是第一个 OrPattern) 的子模式。

您可以通过向第二个 :or 添加虚拟模式来解决此问题,这将强制 groupable? 为 return false:

(match
   [[1 2 3]]
   [(:or [_ _ 2] 
         [1 _ _])] :a0

   [(:or [_ _ 1] 
         [3 _ _]
         :dummy)] :a1
   :else :else)

一个可能更好的 specialize-or-pattern-rowcopy-as 可以通过将 :as 复制到每个 :as子模式):

(defn copy-as [dest src]
  (if-let [as (-> src meta :as)]
    (vary-meta dest assoc :as as)
    dest))

(defn specialize-or-pattern-row [row pat ps]
  (let [p (first row)]
    (if (identical? p pat)
      (map (fn [p] (update-pattern row 0 (copy-as p pat))) ps)
      [row])))

引用 answer from reddit:

Seems like a bug in core.match. I used a slightly simpler statement that has the same problem.

(match
 [[1]]
 [(:or [3] [])] :a0
 [(:or [1] [])] :a1
 :else :else)

This also returns :else. I ran it through macroexpand and extracted the logic. It turns into something like this.

(let
 [x [1]]
  (cond (and (vector? x) (== (count x) 1) (= (nth x 0)  3)) :a0
        (and (vector? x) (== (count x) 0)) :a0
        (and (vector? x) (== (count x) 1) (= (nth x 0) 3)) :a1
        (and (vector? x) (== (count x) 0)) :a1))

On the 5th line there you can see the error, it is 3 instead of 1. For some reason it takes the value that is in the first :or pattern instead of the second rows value.

patch 似乎解决了问题。

谢谢大家!

P.S.: 不过我还没有测试补丁。