2012-01-02 1 views
16

Я только начал играть с core.logic, и для работы над этим я пытаюсь реализовать что-то простое, что похоже на проблему, с которой я сейчас работаю профессионально. Тем не менее, одна часть проблемы заставила меня остановиться ...Как имитировать «внешнее соединение» в core.logic?

Как упрощение моего примера, если у меня есть каталог предметов, а некоторые из них доступны только в некоторых странах, а некоторые из них недоступны в определенных страны. Я хотел бы иметь возможность указать список элементов, и исключения, что-то вроде:

(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, conda в core.logic).

Это решение должно быть вызвано только аргументами заземления.

(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

Под «земельных аргументов», я предполагаю, что вы имеете в виду значение, а не переменные запроса? Извинения, моя последняя кисть с логическим программированием была прологовым курсом undergrad почти 25 лет назад ... –

+1

Это не может быть несвязанная или unground переменная. Значение заземляется, если оно не содержит несвязанных логических переменных (например, [1 2 0._] не измельчается). Это становится актуальным, если функция является целью, и вы передаете переменные запроса в качестве аргументов. В этом контексте «items-colors-for-country» требует, чтобы его первый аргумент был обоснован. Цель более гибкая и сложная, чем мой первоначальный ответ. Например, мы можем запросить цвета Кошельков, доступных в США. https://gist.github.com/1557417 – Ambrose

+0

Спасибо за объяснение! –

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