2013-03-07 14 views
6

我在纏繞clojure和core.logic的時候遇到了麻煩。如何在更大的Clojure程序中以實用的方式使用core.logic?

例如說我有以下問題:

我有鍵值對附帶分數列表:

(:foo "10" 2) 
(:bar "20" 3) 
(:baz "30" 7) 

而且我也有一張地圖:

{:foo "10", 
:bar "42", 
:baz "30"} 

我想要做的是根據地圖評估的分數列表返回分數列表。

使用核心邏輯,我可以做這樣的事情:

(defrel score key value score) 
(fact score :foo "10" 2) 
(fact score :bar "20" 3) 
(fact score :baz "30" 7) 

(run* [q] 
    (conde 
    ((score :foo "10" q)) 
    ((score :baz "30" q)))) 

我也得到了預期的結果:

(2 7) 

我的問題是我不知道如何把它變成的東西,我可以動態地運行一個更大的程序。這意味着我將在不同的時間應用不同的地圖和不同的約束條件。我認爲我可以通過編寫一個函數來創建conde參數,該函數可以接受映射並輸出約束,但是如何在一組臨時事實的上下文中評估?

我當然可以編寫一個函數來返回我想要的但沒有core.logic的東西,但這看起來不那麼優雅。也許我在吠叫錯誤的樹(我對Clojure和core.logic都陌生),這根本不是約束問題。

所以我的問題是:

如何在覈心邏輯混合,當你從一個來源,你不會知道,直到運行時拉你的事實和約束?

和相關的,你如何在一個你想要在一個新的事實環境中評估一組約束的環境中這樣做?

回答

4

要記住的最重要的事情是:關係只是返回目標的函數。 一個目標是一個函數,它可以是succeedfail,所以基本上關係只是更高階的函數。

現在你可以讓你的榜樣,使得關係和各種事實,是在一個單一的功能,並沒有「全局」的關係/事實,可以互相干擾:

(defn find-things [] 
    (letfn [(scoref [key value score] 
      (conde 
      [(== key :foo) (== value "10") (== score 2)] 
      [(== key :bar) (== value "20") (== score 3)] 
      [(== key :baz) (== value "30") (== score 7)]))] 
    (run* [q] 
      (conde 
      ((scoref :foo "10" q)) 
      ((scoref :baz "30" q)))))) 

score只是一個返回目標的函數(使用宏conde

這樣可以解決局部/全局關係問題,但事實和查詢仍然被硬編碼到我們希望作爲參數傳遞的函數中。 一種可能的方法是理解core.logic APIs,它允許你定義動態邏輯變量並統一它們等。我還沒有經過這個API,所以我不能用這個答案回答。另一種方法是使用宏和eval魔法:

(defmacro find-things-generator [data query] 
    (let [key (gensym) value (gensym) score (gensym) q (gensym)] 
    `(letfn [(~'scoref [~key ~value ~score] 
       (conde 
       [email protected](map #(-> [`(== ~key ~(% 0)) 
          `(== ~value ~(% 1)) 
          `(== ~score ~(% 2))]) data) 
       ))] 
     (run* [~q] 
      (conde 
       [email protected](map #(-> [`(~'scoref ~(% 0) ~(% 1) ~q)]) query) 
      ))))) 


(defn find-things [data query] 
    (eval `(find-things-generator ~data ~query))) 

(def data [[:foo "1" 2] 
      [:bar "2" 3] 
      [:baz "3" 7]]) 

(def query {:foo "1", 
      :bar "2", 
      :baz "3"}) 

(find-things data query) 
+0

非常感謝。這使我走上了正確的道路。我需要通過宏來解決這個問題,但這應該有很大的幫助,我非常確定core.logic是我想解決的問題的正確解決方案。 – jgerman 2013-03-13 21:02:21

+0

另請參閱Wiki以使用API​​擴展core.logic的示例https://github.com/clojure/core.logic/wiki/Extending-core.logic-%28Datomic-example%29 – 2015-12-29 03:18:39

3

我也有類似的問題,這裏是我想出了,翻譯成你的問題。

定義您的分數集合。

(def scores 
    [[:foo "10" 2] 
    [:bar "20" 3] 
    [:baz "30" 7]]) 

接下來,定義一個將分數轉換爲關係形式的函數。

(defn scoreso [key value score scores] 
    (conde 
    [(fresh [a] 
     (firsto scores a) 
     (== [key value score] a))] 
    [(fresh [d] 
     (resto scores d) 
     (scoreso key value score d))])) 

最後,確定給定鍵和值的矢量匹配中的哪些分數。

(run* [score] 
    (fresh [key value] 
    (scoreso key value score scores) 
    (conde 
     [(== key :foo) (== value "10")] 
     [(== key :baz) (== value "30")]))) 

這個結果是(2 7)。

該查詢的措辭不同,但它是等同的。

+0

動態查詢怎麼樣? – fmjrey 2014-07-22 09:39:04

相關問題