2012-02-07 11 views
3

の値を取ることができない:Clojureql私は次のように生成する必要がマクロ(Clojureの)

(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

問題は、マクロが機能していないということです - 彼らは、コンパイル時に実行され、実際の構文を渡されます(リストとシンボルは主に)、実行時にランタイムデータ構造に適用することはできません。したがって、(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をしたい - reduceは常にリスト全体を横断しながら、それは、できるだけ早くそれがtrueを返した要素に到達すると停止します。

注:同じ問題が(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]))) 

最後の一つの提案 - あなたは[clojurecl.predicates :as qlp]clojureql.predicatesを交換する場合require clojureql.predicatesは、あなたが上記になり、ファイルの残りの部分でclojureql.predicatesの代わりにqlpを使用することができるとき(我々はまたqlcclojureql.coreを交換した場合):読みする方がはるかに簡単です

(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のwhereは、clojureql.predicates/and*clojureql.or*と表示されているandorを置き換えます。 and*or*はマクロではなく関数なので、問題はありません。

+0

Ret ret、私はあなたの提案を試みましたが、これはclojureqlライブラリでは機能しません。ここで生成するSQLは次のとおりです。SELECT tableA。*、tableA。* FROM tableA JOIN tableA ON((tableA.id = tableB.id)とtableA.id IN(1,2))しかし、私の最初の動作例から)SELECT tableA。*、tableA。* FROM tableA JOIN tableA ON((tableA.id = tableB.id)AND(tableA.id IN(1,2)OR tableA.id IN(3、 4))) –

+0

問題は、clojureQL /は、あなたが渡したソースツリーを歩き回り、数学を探しているマクロで、 'と'と 'または'を探します。通常の環境では、私のコードは正常に動作しますが、これはclojureQLでは機能しません。おそらく回避策はありますが、残念ながらclojureQLは実際には使用しないので、わかりません。私の最終的な提案(リスト操作なし)を行い、my-or-fをマクロにすることは、うまくいくかもしれません。 – Retief

+0

@RonPは私の編集をチェックする - 私はclojureqlソース[ここ](https://github.com/LauJensen/clojureql) – Retief

1

あなたがorを与えているパラメータの量がわかっている場合、これはおそらく最も簡単な解決策です:

(apply #(or %1 %2) [nil 10]) ; => 10 
+0

パラメータの数が異なるため、ハードコードできません。 –

関連する問題