halgari / odin

An embedded extensible logic DSL for Clojure.
183 stars 11 forks source link

How does `and` change bindings? #8

Closed idmitrievsky closed 7 years ago

idmitrievsky commented 7 years ago

In this example

(into {}
  (o/for-query
    (o/and
      (d/query data ?account :credits ?credits)
      (d/query data ?account :debits ?debits)
      (d/query data _ ?name ?account))
    [?account (- ?credits ?debits)]))

#=> {[:jane] 1000,
     [:sue] 3200,
     [:fred] 500,
     [:sam] -80}

it seems like ?account refers to the path it the first two queries as if (d/query data _ ?name ?account) doesn't have any effect. And it doesn't:

(into {}
  (o/for-query
    (o/and
      (d/query data ?account :credits ?credits)
      (d/query data ?account :debits ?debits))
    [?account (- ?credits ?debits)]))

#=> {[:jane] 1000,
     [:sue] 3200,
     [:fred] 500,
     [:sam] -80}

If run separately it produces:

(into []
  (o/for-query
    (o/and
      (d/query data _ ?name ?account))
    [?account]))

#=> [1000
     500
     [:fred]
     [:jane]
     [:sam]
     [:sue]
     2000
     1000
     220
     300
     3300
     100]

that is all values from all levels as expected (except for the weird top-level keys brought up in #7).

So, what happens in the and call? Should it change ?account in some way?

halgari commented 7 years ago

You're right, it doesn't have an affect, and isn't needed in the initial query. I think what I inteded in that example was:


(into {}
  (o/for-query
    (o/and
      (d/query data ?account :credits ?credits)
      (d/query data ?account :debits ?debits)
      (d/query data _ ?name ?account))
    [?name (- ?credits ?debits)]))

#=> {:jane 1000,
         :sue 3200,
         :fred 500,
         :sam -80}

In this example the final clause isn't a constraining clause, it only exists to pull out the name of the account. So it doesn't filter any results it is instead retrieving the name of the account.

idmitrievsky commented 7 years ago

Thank you for the answer! So ?account is bound by the first query and then you're trying to get :debits from all the places where :credits were found?

halgari commented 7 years ago

Correct, the only thing that allows a logic variable to "change values" or be "rebound" is o/or. So in this case, we're looking at the same location for the first two clauses, then looking for the data "above" the account (in the Clojure map) when we look for ?name

idmitrievsky commented 7 years ago

Thanks!