2012-01-02 16 views
16

Tôi mới bắt đầu chơi với core.logic, và để làm việc trên nó, tôi đang cố gắng thực hiện một cái gì đó đơn giản tương tự như một vấn đề mà tôi hiện đang làm việc một cách chuyên nghiệp. Tuy nhiên, một phần của vấn đề đã khiến tôi bối rối ...Làm thế nào để mô phỏng một 'tham gia bên ngoài' trong core.logic?

Làm đơn giản hóa ví dụ của tôi, nếu tôi có một danh mục các mặt hàng và một số mặt hàng chỉ khả dụng ở một số quốc gia nhất định. các quốc gia. Tôi muốn có thể chỉ định danh sách các mục và các trường hợp ngoại lệ, chẳng hạn như:

(defrel items Name Color) 
(defrel restricted-to Country Name) 
(defrel not-allowed-in Country Name) 

(facts items [['Purse 'Blue] 
       ['Car 'Red] 
       ['Banana 'Yellow]]) 

(facts restricted-to [['US 'Car]]) 

(facts not-allowed-in [['UK 'Banana] 
         ['France 'Purse]]) 

Nếu có thể, tôi không muốn chỉ định được phép cho tất cả các quốc gia, vì tập hợp các mục có hạn chế tương đối nhỏ và tôi muốn có thể thực hiện một thay đổi duy nhất để cho phép/loại trừ một mục cho một quốc gia cụ thể.

Làm thế nào tôi có thể viết một quy luật cung cấp cho các danh sách các mục/màu sắc cho một quốc gia, với những hạn chế sau:

  • Mục phải nằm trong danh sách các mục
  • Đất nước/mục phải được không có trong danh sách 'không-phép-in'
  • Hoặc:
    • không có nước trong restricted-liệt kê cho rằng mục
    • cặp quốc gia/item là trong restricted- để liệt kê

Có cách nào để thực hiện việc này không? Tôi có đang suy nghĩ về mọi thứ theo cách hoàn toàn sai lầm không?

Trả lời

14

Thông thường khi bạn bắt đầu phủ nhận các mục tiêu trong lập trình logic, bạn cần tiếp cận các hoạt động phi quan hệ (cắt trong Prolog, conda trong core.logic).

Giải pháp này chỉ nên được gọi với đối số mặt đất.

(defn get-items-colors-for-country [country] 
    (run* [q] 
    (fresh [item-name item-color not-country] 
     (== q [item-name item-color]) 
     (items item-name item-color) 
     (!= country not-country) 

     (conda 
     [(restricted-to country item-name) 
     (conda 
      [(not-allowed-in country item-name) 
      fail] 
      [succeed])] 
     [(restricted-to not-country item-name) 
     fail] 
     ;; No entry in restricted-to for item-name 
     [(not-allowed-in country item-name) 
     fail] 
     [succeed])))) 

(get-items-colors-for-country 'US) 
;=> ([Purse Blue] [Banana Yellow] [Car Red]) 

(get-items-colors-for-country 'UK) 
;=> ([Purse Blue]) 

(get-items-colors-for-country 'France) 
;=> ([Banana Yellow]) 

(get-items-colors-for-country 'Australia) 
;=> ([Purse Blue] [Banana Yellow]) 

Full solution

+0

By 'đối số mặt đất', tôi giả sử bạn có nghĩa là một giá trị, chứ không phải là các biến truy vấn? Xin lỗi, bàn chải cuối cùng của tôi với lập trình logic là một khóa học prolog trải qua gần 25 năm trước ... –

+1

Nó không thể là một biến unbound hoặc unground. Một giá trị là mặt đất nếu nó không chứa các biến logic không liên kết (ví dụ: [1 2 0._] không phải là mặt đất). Điều này trở nên có liên quan nếu hàm là một mục tiêu và bạn đang truyền các biến truy vấn làm đối số. Trong ý chính này, 'items-colors-for-country' yêu cầu đối số đầu tiên của nó là mặt đất. Mục tiêu là linh hoạt hơn và có thể tổng hợp hơn câu trả lời ban đầu của tôi. Ví dụ, chúng tôi có thể truy vấn màu sắc của ví có sẵn ở Mỹ. https://gist.github.com/1557417 – Ambrose

+0

Cảm ơn bạn đã giải thích! –

2

Conda thể complexifies mã, sử dụng nafc, bạn có thể dễ dàng hơn sắp xếp lại các mục tiêu nếu bạn muốn. Điều này vẫn không quan hệ! :)

(ns somenamespace 
    (:refer-clojure :exclude [==]) 
    (:use [clojure.core.logic][clojure.core.logic.pldb])) 

(db-rel items Name Color) 
(db-rel restricted-to Country Name) 
(db-rel not-allowed-in Country Name) 

(def stackoverflow-db 
    (db [items 'Purse 'Blue] 
     [items 'Car 'Red] 
     [items 'Banana 'Yellow] 
     [restricted-to 'US 'Car] 
     [not-allowed-in 'UK 'Banana] 
     [not-allowed-in 'France 'Purse])) 


(defn get-items-colors-for-country [country] 
    (with-db stackoverflow-db 
    (run* [it co] 
     (items it co) 
     (nafc not-allowed-in country it) 
     (conde 
      [(restricted-to country it)] 
      [(nafC#(fresh [not-c] (restricted-to not-c %)) it)])))) 

(get-items-colors-for-country 'US) 
;=> ([Purse Blue] [Banana Yellow] [Car Red]) 

(get-items-colors-for-country 'UK) 
;=> ([Purse Blue]) 

(get-items-colors-for-country 'France) 
;=> ([Banana Yellow]) 

(get-items-colors-for-country 'Australia) 
;=> ([Purse Blue] [Banana Yellow]) 

Để biết thêm ví dụ: https://gist.github.com/ahoy-jon/cd0f025276234de464d5