2013-03-07 28 views
6

Tôi đang gặp khó khăn khi quấn đầu quanh cách trộn clojure và core.logic.Làm thế nào để bạn sử dụng core.logic một cách thiết thực trong một chương trình Clojure lớn hơn?

Ví dụ nói rằng tôi có vấn đề sau đây:

Tôi có một danh sách các cặp giá trị key với điểm kèm theo:

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

Và tôi cũng có một bản đồ:

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

Điều tôi muốn làm là trả lại danh sách điểm số dựa trên danh sách điểm số được đánh giá theo bản đồ.

Sử dụng logic lõi tôi có thể làm một cái gì đó như thế này:

(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)))) 

Và tôi nhận được kết quả dự kiến:

(2 7) 

Vấn đề của tôi là tôi không thấy làm thế nào để tắt chức năng này thành một cái gì đó Tôi có thể chạy trong một chương trình lớn hơn động. Có nghĩa là tôi sẽ có các bản đồ khác nhau và các ràng buộc khác nhau để áp dụng vào các thời điểm khác nhau. Tôi nghĩ rằng tôi có thể tạo ra các đối số để conde bằng cách viết một chức năng mà có bản đồ và đầu ra các ràng buộc, nhưng làm thế nào để tôi có chạy * đánh giá trong bối cảnh của một tập hợp các sự kiện tạm thời?

Tôi chắc chắn có thể viết một hàm để trả lại những gì tôi muốn mà không có core.logic, nhưng điều đó có vẻ kém thanh lịch hơn. Có lẽ tôi đang sủa cây sai (tôi mới dùng cả Clojure và core.logic) và đây không phải là vấn đề khó khăn.

Vì vậy, câu hỏi của tôi là:

Làm thế nào để bạn kết hợp trong logic lõi khi bạn kéo các sự kiện và những hạn chế của bạn từ một nguồn bạn sẽ không biết cho đến khi thời gian chạy?

Và có liên quan, bạn làm như thế nào trong một môi trường mà bạn muốn đánh giá một tập hợp các ràng buộc trong môi trường thực tế mới?

Trả lời

4

Điều quan trọng nhất cần nhớ là: Quan hệ chỉ là chức năng trả về mục tiêu. Mục tiêu là một chức năng có thể succeed hoặc fail, do đó, về cơ bản mối quan hệ chỉ là hàm bậc cao hơn.

Bây giờ bạn có thể làm ví dụ của bạn như vậy mà các mối quan hệ và các sự kiện khác nhau đang ở trong một chức năng duy nhất và không có "toàn cầu" liên quan/sự kiện mà có thể giao thoa với nhau:

(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 chỉ là một hàm trả về một mục tiêu (sử dụng macro conde)

Điều này giải quyết được vấn đề quan hệ cục bộ/toàn cầu, nhưng vẫn còn sự thật và truy vấn được mã hóa vào hàm mà chúng tôi muốn chuyển như trong tham số. Một cách có thể để làm điều đó là hiểu các API core.logic cho phép bạn xác định các vlog logic động và thống nhất chúng, v.v. Tôi đã không thông qua API đó nên tôi sẽ không thể trả lời bằng cách sử dụng nó.Một cách khác sẽ được sử dụng macro và eval kỳ diệu:

(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

Xin cảm ơn. Điều này đã khiến tôi đi đúng hướng. Tôi sẽ cần phải làm việc thông qua các macro nhưng điều này sẽ giúp rất nhiều và tôi khá chắc chắn core.logic là giải pháp đúng cho vấn đề tôi muốn giải quyết. – jgerman

+0

Xem thêm wiki ví dụ về việc mở rộng core.logic bằng cách sử dụng API https://github.com/clojure/core.logic/wiki/Extending-core.logic-%28Datomic-example%29 –

3

Tôi đã có một câu hỏi tương tự và đây là những gì tôi đã đưa ra, phiên dịch sang vấn đề của bạn.

Xác định tập hợp điểm số của bạn.

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

Tiếp theo, xác định hàm sẽ chuyển đổi điểm thành dạng quan hệ.

(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))])) 

Cuối cùng, xác định điểm số nào trong vectơ khớp với khóa và giá trị nhất định.

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

Kết quả này là (2 7).

Truy vấn được diễn đạt khác nhau, nhưng nó tương đương.

+0

Điều gì về các truy vấn động? – fmjrey

Các vấn đề liên quan