core-logic

tsdh 2015-07-31T07:12:07.000068Z

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)...

tsdh 2015-07-31T07:17:04.000069Z

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...

tsdh 2015-07-31T07:27:52.000070Z

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

tsdh 2015-07-31T07:37:07.000071Z

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

nberger 2015-07-31T15:20:48.000072Z

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

nberger 2015-07-31T15:22:12.000073Z

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)))
;=> ()

nberger 2015-07-31T15:23:45.000075Z

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))

nberger 2015-07-31T15:24:47.000076Z

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

nberger 2015-07-31T15:29:10.000077Z

a smaller example:

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

nberger 2015-07-31T15:47:55.000078Z

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))

nberger 2015-07-31T15:48:19.000079Z

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))

tsdh 2015-07-31T16:13:02.000080Z

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

tsdh 2015-07-31T16:15:49.000081Z

...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."

tsdh 2015-07-31T16:20:46.000082Z

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.

tsdh 2015-07-31T16:22:09.000083Z

Probably you meant this:

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

nberger 2015-07-31T16:30:08.000084Z

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

tsdh 2015-07-31T16:41:42.000085Z

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

nberger 2015-07-31T16:42:06.000086Z

yep :simple_smile: