tonsky / datascript

Immutable database and Datalog query engine for Clojure, ClojureScript and JS
Eclipse Public License 1.0
5.49k stars 309 forks source link

difference between rule and added pattern variables ? #87

Closed ThomasDeutsch closed 9 years ago

ThomasDeutsch commented 9 years ago

For this example, a simple rule is not working, and i do not know why. At first the working example, and then the same task with a rule.

Example: The last from the first task-list matches the first from the second task-list. For this Example [1 2 3] [3 4 5] is valid and [3 4 5] [1 2 3] is not.

 {:db/id 1
   :tasks [1 2 3]}   ;; not cardinality/many ( to keep ordering )
{:db/id 2
  :tasks [3 4 5]}

(defn find-combinations [db]
  (d/q '[:find ?s1 ?s2
         :in $ ?first ?last
         :where
         [?s1 :tasks ?t1]
         [?s2 :tasks ?t2]
         [(not= ?s1 ?s2)]
         [(?last ?t1) ?x]
         [(?first ?t2) ?y]
         [(= ?x ?y)]]
            db first last))

->  [1 2]   ;; correct !

Same thing, as a rule:

(def filter-rule
  '[[(fits ?t1 ?t2 ?first ?last)
     [(= (?last ?t1) (?first ?t2))]]])

(defn find-combinations [db]
  (d/q '[:find ?s1 ?s2
         :in $ % ?first ?last
         :where
         [?s1 :tasks ?t1]
         [?s2 :tasks ?t2]
         [(not= ?s1 ?s2)]
         (fits ?t1 ?t2 ?first ?last)
            db filter-rule first last))

-> [1 2] [2 1]   ;; not correct !

it seems to ignore the rule - what is my mistake?

Is it because datascript can not (= (fncall ...) (fncall ...)) and needs two pattern variables instead?

tonsky commented 9 years ago

datascript can not (= (fncall ...) (fncall ...)) and needs two pattern variables instead

You’re right, that’s the limitation of Datalog. You can introduce new variables in rule as well:

(def filter-rule
  '[[(fits ?t1 ?t2 ?first ?last)
     [(?last ?t1) ?x]
     [(?first ?t2) ?y]
     [(= ?x ?y)]]])