Clojure 将插入事实从Prolog转换为core.logic

Clojure 将插入事实从Prolog转换为core.logic,clojure,prolog,clojure-core.logic,Clojure,Prolog,Clojure Core.logic,我在玩弄core.logic,试图翻译一些Prolog代码,并对插入的事实进行无休止的递归(摘自R.A.O'Keefe的“Prolog工艺”): 这就是我到目前为止所提到的(请注意,前两个参数被交换以匹配conso参数列表): 我的问题是,这些midje测试的最后两个事实永远不会回来。 第一个操作与预期一样正常,因为这只需要第一个conso子句 (fact "Inserting works" (run* [q] (insert 1 [2] q)) => '((1 2

我在玩弄core.logic,试图翻译一些Prolog代码,并对插入的
事实进行无休止的递归(摘自R.A.O'Keefe的“Prolog工艺”):

这就是我到目前为止所提到的(请注意,前两个参数被交换以匹配
conso
参数列表):

我的问题是,这些midje测试的最后两个事实永远不会回来。 第一个操作与预期一样正常,因为这只需要第一个
conso
子句

   (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))))
我想我忽略了一些显而易见的事情,但是什么呢

编辑:事实不能正确反映Prolog代码的行为。正确的行为是这样的:

   ?- insert([2,3], 1, Q).
   Q = [1, 2, 3] ;
   Q = [2, 1, 3] ;
   Q = [2, 3, 1].
所以,第二个可检查项实际上应该是

 (fact "Inserting works"
       (run* [q] (insert 1 [2 3] q)) => '((1 2 3) (2 1 3) (2 3 1)))

解决方案是将递归insert子句设置为最后一个:

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

Prolog代码几乎可以作为核心逐字转录。逻辑还支持匹配

(defne inserto [L, X, L*] 
    ([L, X, (X . L)]) 
    ([(H . T), X, (H . L)] (inserto T, X, L)))
请注意,我保持了Prolog版本的顺序,而不是版本中前两个逻辑变量的倒序

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

谢谢我必须想一想为什么顺序的改变会在这里产生影响。为了说明Prolog版本的正确行为(参见我上面的编辑),
l
应该只在第一个
conso
术语中使用,并用新的
l1
替换。请注意@Ankur回答了实际问题,但我觉得这是很有用的,不适合发表评论。谢谢你对匹配的提示,这确实让它更容易。然而,正如我发现的,这个解决方案与Prolog版本的行为不匹配,这可能是因为我把midje的事实弄错了(我编辑了这个问题来纠正它)。不过,它只需要一点小小的改变:将递归代码中“L”的用法与L1交换,即
([H.T),X,(H.L1)](inserto T,X,L1)
。这允许通过回溯找到更多结果。使用
NL=[H | R]
。无法在此处使用
L
而不是
R
L
已用作参数。
(defne inserto [L, X, L*] 
    ([L, X, (X . L)]) 
    ([(H . T), X, (H . L)] (inserto T, X, L)))
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))