2012-01-02 8 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]]) 

可能な場合は、私はむしろ許さ-で指定していないと思い、すべての国のために、制限のあるアイテムのセットとして比較的小さいので、特定の国のアイテムの許可/拒否を1回変更できるようにしたいと考えています。アイテムは、アイテム

  • の一覧で国/項目でなければなりません

    • 必要があります:どのように私は次の制約で、国のためのアイテム/色のリストを与えるルールを記述することができます

      「-許可されていないイン」リストに

    • のどちらかではないこと:には国はありません
      • 制限-し、その項目
      • 国/アイテムのペアがrestricted-であるためリスト

    これを行うにはいくつかの方法がありますの一覧を表示するには?私は事を完全に間違った方法で考えていますか?あなたは論理プログラミングでゴールを否定起動したときに

  • 答えて

    14

    は通常、あなたは非リレーショナル操作(プロローグでカット、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年前に学部のプロローグコースでした... –

    +1

    これはアンバウンドまたはアングラウンド変数にすることはできません。アンバウンド論理変数が含まれていない場合は、値はグラウンドになります([1 2 0._]はグラウンドではありません)。関数が目標で、クエリ変数を引数として渡している場合、これは関連します。この要点では、 'item-colors-for-country'は、最初の引数が必要です。目標は私の最初の答えよりも柔軟性があり、構成可能です。たとえば、米国で入手可能な小銭の色を照会することができます。 https://gist.github.com/1557417 – Ambrose

    +0

    説明をありがとう! –

    2

    Condaは、あなたがしたい場合は、より簡単にゴールを並べ替えることができ、nafcを使用して、コードをcomplexifiesことがあります。 これはまだ非リレーショナルです! :)例について

    (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