如何模拟core.logic中的“外连接”?

时间:2012-01-02 20:25:34

标签: clojure logic clojure-core.logic minikanren

我刚开始玩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]])

如果可能的话,我宁愿不为所有国家指定允许,因为有限制的项目集相对较小,我希望能够进行一次更改以允许/排除某个项目对于某个国家。

如何编写一个规则,列出国家/地区的项目/颜色列表,并具有以下约束:

  • 该项目必须位于项目列表
  • 国家/项目必须不在“不允许进入”列表中
  • 或者:
    • 该项目的限制列表中没有国家/地区
    • 国家/项目对位于限制列表

有没有办法做到这一点?我是以完全错误的方式思考问题吗?

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

Conda可能会使代码变得复杂化,使用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