首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Clojureql -无法获取宏的值(clojure)

Clojureql -无法获取宏的值(clojure)
EN

Stack Overflow用户
提问于 2012-02-08 01:52:47
回答 2查看 2.1K关注 0票数 3

我需要生成以下代码:

代码语言:javascript
复制
(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])])])))

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

代码语言:javascript
复制
(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)])))

其中,此函数为:

代码语言:javascript
复制
(defn my-or-f []
    (apply or [(clojureql.predicates/in :tableA.id [1 2])
         (clojureql.predicates/in :tableA.id [3 4])]))

然而,这个函数抛出了这个异常:

代码语言:javascript
复制
#<CompilerException java.lang.Exception: Can't take value of a macro: #'clojure.core/or (NO_SOURCE_FILE:2)>

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

代码语言:javascript
复制
(defmacro my-or-f []
    `(apply or [(clojureql.predicates/in :tableA.id [1 2])
         (clojureql.predicates/in :tableA.id [3 4])]))

有没有其他方式可以让我使用“应用或者”?

谢谢。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-02-08 06:30:57

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

代码语言:javascript
复制
(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呢?这应该也能很好地工作:

代码语言:javascript
复制
(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时,如果你用[clojurecl.predicates :as qlp]代替clojureql.predicates,你可以在文件的其余部分用qlp代替clojureql.predicates,这就是上面(如果我们也用qlc代替clojureql.core ):

代码语言:javascript
复制
(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的whereclojureql.predicates/and*clojureql.or*替换了它看到的任何andor,所以您自己做这个替换应该是可行的。and*or*都是函数,而不是宏,所以应该不会有任何问题。

票数 4
EN

Stack Overflow用户

发布于 2012-02-08 04:38:01

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

代码语言:javascript
复制
(apply #(or %1 %2) [nil 10]) ; => 10
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9181231

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档