2
votes

I'm toying around with core.logic and trying to translate some Prolog code and run into an endless recursion for the insert facts (taken from R.A.O'Keefe's "Craft of Prolog"):

 insert(L, X, [X|L]).
 insert([H|T], X, [H|L]) :-
        insert(T,X,L).

This is what I've come up so far (please note that the first two arguments are exchanged to match up with conso parameter list):

 (defn insert [x l nl]
    (conde
      [(conso x l nl)]
      [(fresh [h t]
         (conso h t l)
         (insert x t l)
         (conso h l nl))]))

The problem I have is that the last two facts from these midje tests will never return. The first one works just fine as is expected since this only requires the first conso clause.

   (fact "Inserting works"
         (run* [q] (insert 1 [2] q)) => '((1 2)))
         (run* [q] (insert 1 [2 3] q)) => '((1 2 3)))
   (fact "We can retrieve the inserted data"
         (run* [q] (insert q [2] '(1 2))) => '(1))
   (fact "We can retrieve the list data, too"
         (run* [q] (insert 1 q '(1 2))) => '((2))))

I guess I'm overlooking something obvious, but what?

Edit: The facts don't reflect the behavior of the Prolog code correctly. The right behavior is like this:

   ?- insert([2,3], 1, Q).
   Q = [1, 2, 3] ;
   Q = [2, 1, 3] ;
   Q = [2, 3, 1].

So, the second checkable should actually be

 (fact "Inserting works"
       (run* [q] (insert 1 [2 3] q)) => '((1 2 3) (2 1 3) (2 3 1)))
2
use NL=[H|R]. can't use L instead of R there, L is already used as an argument.Will Ness

2 Answers

3
votes

The solution is to make the recursive insert clause last:

(defn insert [x l nl]
    (conde
      [(conso x l nl)]
      [(fresh [h t]
         (conso h t l)
         (conso h l nl)
         (insert x t l))]))
3
votes

The Prolog code can be transcribed almost verbatim as core.logic also supports matching.

(defne inserto [L, X, L*] 
    ([L, X, (X . L)]) 
    ([(H . T), X, (H . L)] (inserto T, X, L)))

Note that I've kept the order of the Prolog version, rather than the inverted order of the first two logical variables in your version.

user=> (run* [q] (inserto [2] 1 q))
((1 2))
user=> (run* [q] (inserto [2 3] 1 q))
((1 2 3))
user=> (run* [q] (inserto [2] q [1 2]))
(1)
user=> (run* [q] (inserto q 1 [1 2]))
((2))