2012-01-02 23 views
16

我剛剛開始玩core.logic,並努力工作,我試圖實現一些簡單的事情,類似於我目前正在專業工作的問題。然而,這個問題的一個部分讓我難住...如何模擬core.logic中的'outer join'?

作爲我的例子的簡化,如果我有一個項目的目錄,其中一些只在某些國家可用,有些不具體在特定國家。我希望能夠指定的項目清單,以及例外情況,是這樣的:

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

如果可能的話,我寧願不指定允許,在所有國家,作爲組項目有限制相對較小,我希望能夠對特定國家/地區的項目進行單一更改以允許/排除。

我如何寫一個規則,給出的項目/顏色列表對於一個國家,有以下限制:

  • 該項目必須在項目
  • 國家/項目必須名單將不會在「不被允許入名單
  • 或者:
    • 有沒有一個國家的限制,列出該項目
    • 國家/項目對處於restricted-列出

是否有某種方式來做到這一點?我是以完全錯誤的方式思考事物嗎?

回答

14

通常,當您開始否定邏輯編程中的目標時,您需要達成非關係操作(在Prolog中切入,在core.logic中切入conda)。

該解決方案只應使用地面參數進行調用。

(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

通過「地面論據」,我想你指的是價值,而不是查詢變量?道歉,我最後一次使用邏輯編程的筆刷在25年前是一本本科的prolog課程... – 2012-01-03 22:31:22

+1

它不能是一個未綁定或未經過處理的變量。如果某個值不包含未綁定的邏輯變量(例如,[1 2 0._]未接地),則該值爲接地。如果函數是一個目標,並且您將查詢變量作爲參數傳遞,這將變得相關。在這個要點中,'items-colors-for-country'需要首先論證它的第一個論點。目標比我最初的答案更加靈活和可組合。例如,我們可以查詢在美國可用的錢包的顏色。 https://gist.github.com/1557417 – Ambrose 2012-01-03 23:14:30

+0

感謝您的解釋! – 2012-01-04 03:33:03

2

康達可以complexifies代碼,使用NAFC,你可以,如果你想更輕鬆地重新排序的目標。 這仍然是非關係! :)

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

更多的例子:https://gist.github.com/ahoy-jon/cd0f025276234de464d5