3

我需要生成以下内容:

(clojureql.core/join (clojureql.core/table db :tableA) (clojureql.core/table db :tableA)
     (clojureql.core/where (apply and (= :tableA.id :tableB.id)
                      [(apply or [(clojureql.predicates/in :tableA.id [1 2])
                                  (clojureql.predicates/in :tableA.id [3 4])])])))

但是“应用或”表单需要从另一个函数或宏“传递”。这就是我的意思:

(clojureql.core/join (clojureql.core/table db :tableA) (clojureql.core/table db :tableA)
     (clojureql.core/where (apply and (= :tableA.id :tableB.id)
                      [(my-or-f)])))

这个函数是:

(defn my-or-f []
    (apply or [(clojureql.predicates/in :tableA.id [1 2])
         (clojureql.predicates/in :tableA.id [3 4])]))

但是这个函数抛出了这个异常:

#<CompilerException java.lang.Exception: Can't take value of a macro: #'clojure.core/or (NO_SOURCE_FILE:2)>

我也尝试过使用宏。它可以编译,但是当我尝试使用此宏运行查询时会引发相同的异常

(defmacro my-or-f []
    `(apply or [(clojureql.predicates/in :tableA.id [1 2])
         (clojureql.predicates/in :tableA.id [3 4])]))

还有其他方法可以使用“应用或”吗?

谢谢。

4

2 回答 2

4

问题是宏不是函数 - 它们在编译时运行并传递实际语法(主要是列表和符号),因此您不能在运行时将它们应用于运行时数据结构。因此,(apply or my-list)引发错误。你有几个选择:

(def my-list (list false false 4 false 5))

(some identity my-list) -- returns 4
(reduce #(or %1 %2) my-list) -- returns 4

在实践中,您可能想要some——它在到达返回 true 的元素时立即停止,同时reduce始终遍历整个列表。

注意:你也会有同样的问题(apply and ...)-(every? identity ...)会做你想做的事。

但是,在这种情况下,您为什么需要使用apply呢?这应该同样有效:

(clojureql.core/join (clojureql.core/table db :tableA) (clojureql.core/table db :tableA)
                     (clojureql.core/where (and (= :tableA.id :tableB.id)
                                                (my-or-f))))

(defn my-or-f []
  (or (clojureql.predicates/in :tableA.id [1 2])
      (clojureql.predicates/in :tableA.id [3 4])))

最后一个建议 - 当您require使用 clojureql.predicates 时,如果您替换clojureql.predicates[clojurecl.predicates :as qlp],则可以在文件的其余部分中使用qlp代替clojureql.predicates,这使得上述内容(如果我们也替换clojureql.coreqlc):

(qlc/join (qlc/table db :tableA) (qlc/table db :tableA)
          (qlc/where (and (= :tableA.id :tableB.id)
                          (my-or-f))))

(defn my-or-f []
  (or (qlp/in :tableA.id [1 2])
      (qlp/in :tableA.id [3 4])))

这更容易阅读。

对于 ClojureQL,请尝试(apply clojureql.predicates/or* ...)使用(apply clojureql.predicates/and* ...). clojureql'swhere替换 anyand并且or它看到clojureql.predicates/and*and clojureql.or*,所以自己做这个替换应该可以工作。两者都是函数,and*or*不是宏,所以应该没有任何问题。

于 2012-02-07T22:30:56.650 回答
1

如果您给出的参数数量or是已知的,这可能是最简单的解决方案:

(apply #(or %1 %2) [nil 10]) ; => 10
于 2012-02-07T20:38:01.257 回答