Fork me on GitHub
#core-logic
<
2015-07-31
>
tsdh07:07:07

Hm, can anyone explain this?

(run* [q]
  (fresh [a b]
    (== q (list a b))
    (fd/in a b (fd/interval 1 3))
    (fd/< a b)
    (nafc membero 2 q)))
;=> ((1 2) (2 3) (1 3))
The negation as failure constraint is supposed to ensure that 2 is not a member of the list q, so I expected to get only the solution (1 3)...

tsdh07:07:04

It works if I replace the constraint with (nafc == a 2) (nafc == b 2) or (!= a 2) (!= b 2) but that gets cumbersome if the length of the list collection is long or even unknown...

tsdh07:07:52

Well, I think this is a bug so I've reported it: http://dev.clojure.org/jira/browse/LOGIC-172

tsdh07:07:07

Hm, it seems the problem only occurs stuff unified by clojure.core.logic.fd relations...

nberger15:07:48

@tsdh it's not an issue with fd, but it's because a and b are not ground. nafc works only on grounded terms

nberger15:07:12

So the following does what you expected:

(run* [q]
        (fresh [a b]
               (== q (list a b))
               (fd/in a b (fd/interval 1 3))
               (fd/< a b)
               (== a 1)
               (== b 2)
               (l/nafc l/membero 2 q)))
;=> ()

nberger15:07:45

while the following doesn't:

(run* [q]
        (fresh [a b]
               (== q (list a b))
               (fd/in a b (fd/interval 1 3))
               (fd/< a b)
               (== a 1)
               (l/nafc l/membero 2 q)
               (== b 2)))
;=> ((1 2))

nberger15:07:47

in the second example, b is not ground for the nafc

nberger15:07:10

a smaller example:

(run* [q]
        (membero q [1 2])
        (nafc membero 2 q))
  ;=> (1 2)

nberger15:07:55

One way to accomplish what you were trying:

(run* [q]
    (fresh [a b]
      (== q (list a b))
      (fd/in a b (fd/interval 1 3))
      (fd/< a b)
      (everyg #(!= 2 %) q)))
  ;=> ((1 3))

nberger15:07:19

And if you have an arbitrary number of vars:

(let [vars (map lvar (range 4))]
    (run* [q]
      (== q vars)
      (everyg #(fd/in % (fd/interval 1 6)) vars)
      (everyg #(apply fd/< %) (partition 2 1 vars))
      (everyg #(!= 2 %) q)))
  ;=> ((1 3 4 5) (3 4 5 6) (1 4 5 6) (1 3 5 6) (1 3 4 6))

tsdh16:07:02

@nberger: But the nafc docs say that if the vars aren't ground, the evaluation of the constraint will be deferred.

tsdh16:07:49

...which I read as "it should work also for fresh vars where the actual check is deferred until the point where all vars are ground."

tsdh16:07:46

I think your smaller example is wrong. q takes the values 1 and 2, and of course (membero 2 1) and (membero 2 2) fail.

tsdh16:07:09

Probably you meant this:

(run* [q]
        (== q [1 2])
        (nafc membero 2 q))
;=> ()
which actually gives the right answer.

nberger16:07:08

Yes, sorry, my example was wrong, so nafc is doing fine in that case. And reading again, I agree, deferred evaluation should do what you said

tsdh16:07:42

Well, we'll see if someone with more knowledge on the implementation comments on the JIRA issue.