【问题标题】:Filter being too aggressive过滤器过于激进
【发布时间】:2015-12-07 21:05:15
【问题描述】:

我已尽量避免完全理解代码,因此请先阅读整个问题,然后在必要时深入研究代码。

我正在尝试制作一个用于模式匹配的宏。 它的工作原理是获取一个列表,其中第一个元素是要执行的匹配类型

示例:列表中的第一个元素是“cons”;该宏将调用一个缺点匹配函数。

匹配函数接受一个对象和一个函数,调用具有匹配值的函数。使用 cons 匹配器,它将使用列表的头部和尾部调用函数。

我使用“num”匹配器进行测试。它基本上是一个身份匹配器,所以它可以任意嵌套在自己内部,就像我在下面所做的那样。

;a macro to make debugging easier
(defmacro log [item] `(do (print ~(join [(str item) ": "])) (println ~item)))

(defn make-pattern-matcher-iter [result bindings-queue]
  (println "starting next iteration")
  (log bindings-queue)
  (if (first bindings-queue) (println "bindings-queue does contain an element") nil)
  (if (first bindings-queue)
    (let [[next-symbol pattern] (first bindings-queue)
          pattern-name (first pattern)
          pattern-items (next pattern)
          pattern-matching-function (prepend-symbol "match-" pattern-name)
          gensyms-attached-to-subpatterns (map (fn [pattern]
                                                (if (symbol? pattern)
                                                  pattern
                                                  `(~(gensym "matchbinding") ~pattern)))
                                              pattern-items)
          all-bound-symbols (map (fn [sym]
                                  (if (symbol? sym) sym (first sym)))
                                gensyms-attached-to-subpatterns)
          gensyms-subpattern-pairs (filter list? gensyms-attached-to-subpatterns)
          rest-of-bindings-queue (next bindings-queue)
          updated-bindings-queue (concat rest-of-bindings-queue 
                                        gensyms-subpattern-pairs)
          subpatterns (map second gensyms-subpattern-pairs)]
      (log next-symbol)
      (log all-bound-symbols)
      (log updated-bindings-queue)
      (log gensyms-attached-to-subpatterns)
      (log gensyms-subpattern-pairs)
      (log subpatterns)
      `(~pattern-matching-function
        ~next-symbol 
        (fn [~@all-bound-symbols] ~(make-pattern-matcher-iter result updated-bindings-queue))))
    result))

(defn make-pattern-matcher [object pattern result] (make-pattern-matcher-iter result [[object pattern]]))


(defn match-num [x f]
  (if (number? x) (f x) nil))


(def this-m (make-pattern-matcher-iter '(+ x y) [['object '(pair x y)]]))
(def this-n (make-pattern-matcher '15 '(num (num z)) 'z))
(= this-n this-m)

(defmacro bind-match [object pattern result] (make-pattern-matcher object pattern result))

(bind-match 15 (num (num z)) z)

问题是宏没有正确绑定“z”

日志给出了第二次迭代:

gensyms-attached-to-subpatterns: ((matchbinding8210 (num z)))
gensyms-subpattern-pairs: ()

还有其他日志消息,但这些似乎是问题所在。

看看gensyms-subpattern-pairs是如何计算的。在 let 块中它说:

gensyms-subpattern-pairs (filter list? gensyms-attached-to-subpatterns)

这应该取出除列表之外的所有内容,这是所有内容,因此它不应该取出任何内容。 过滤器似乎过于激进。为什么?

【问题讨论】:

  • (map type gensyms-attached-to-subpatterns) 提供了什么?
  • @Elogent 它给了(clojure.lang.Cons)。缺点的列表还在吗?
  • @Elogent 啊哈,(list? (cons 4 [5])) 返回 false。如果你想给出答案,我会接受。

标签: clojure macros


【解决方案1】:

如您所述,gensyms-attached-to-subpatterns 的元素不是IPersistentLists,而是Conses。健全性检查:

(contains? (supers clojure.lang.Cons) clojure.lang.IPersistentList)
;=> false

所以看起来您需要使用除 list? 之外的其他检查。

【讨论】:

  • 具体我用seq?
猜你喜欢
  • 2017-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-01
  • 1970-01-01
相关资源
最近更新 更多