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

时间:2017-05-04 12:01:22

标签: clojure pattern-matching clojure-core.match

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

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

=> :else

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

怪异。

这有效:

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

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

=> :a0

这是预期的行为吗?

3 个答案:

答案 0 :(得分:3)

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

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

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

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

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

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

答案 1 :(得分:2)

我认为这是specialize-or-pattern-row中的错误。我相信groupable?测试是错误的,因为在您的情况下,它会成功用于您的两个OrPattern,因此第二个OrPattern将替换为第一个ps的扩展({ {1}}是第一个OrPattern的子模式。

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

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

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

可能会更好specialize-or-pattern-row copy-as通过将:as复制到每个子模式来保留整个OrPattern上的任何: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])))

答案 2 :(得分:0)

引用answer from reddit

  

看起来像core.match中的错误。我使用了一个稍微简单的语句来解决同样的问题。

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

这也会返回:else。我通过macroexpand运行它并提取逻辑。它变成了这样的东西。

(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))
  

在第5行,你可以看到错误,它是3而不是1.由于某种原因,它采用第一个:或模式而不是第二行值的值。

似乎这个patch解决了这个问题。

谢谢大家!

P.S。:我还没有对这个补丁进行测试。