【问题标题】:How to simulate an 'outer join' in core.logic?如何在 core.logic 中模拟“外部连接”?
【发布时间】:2012-02-01 01:31:53
【问题描述】:

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

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

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

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

有没有办法做到这一点?我是否以完全错误的方式思考事情?

【问题讨论】:

    标签: clojure logic clojure-core.logic minikanren


    【解决方案1】:

    通常当您开始否定逻辑编程中的目标时,您需要接触非关系操作(Prolog 中的 cut,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

    【讨论】:

    • 通过“基本参数”,我假设您的意思是一个值,而不是查询变量?抱歉,我最后一次接触逻辑编程是大约 25 年前的本科序言课程......
    • 它不能是未绑定或未接地的变量。如果一个值不包含未绑定的逻辑变量(例如 [1 2 0._] 不是接地),则该值是接地的。如果函数是一个目标并且您将查询变量作为参数传递,这将变得相关。在这个要点中,items-colors-for-country 要求它的第一个参数是接地的。目标比我最初的答案更灵活和可组合。例如,我们可以查询美国可用的钱包颜色。 gist.github.com/1557417
    • @PeterHart 我假设这个基于的专业项目是基于数据库的?如果您有兴趣扩展 core.logic 以直接查询此数据库,我已经转储了一些资料 here
    • 实际上这一切都是使用集合(java 代码)和/或 xpath 查询在内存中完成的。实际问题要复杂得多——它涉及重叠的层次结构。不幸的是,我进入环境的机会相当渺茫。不过,我会看看你的例子,因为我试图理解这一点,以便如果我有机会提出案例,我将有足够的知识来做好工作。
    【解决方案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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-09-01
      • 2011-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-06-08
      相关资源
      最近更新 更多