刚开始使用core.logic,版本"0.8.11":
(q/run* [q]
(q/fresh [a]
(q/membero a [2 3]))
(q/membero q [1]))
我不明白结果:(1 1)
。
我的理解是,我用fresh创建了另一个变量a
,它可以取2或3的值。并且CCD_ 3可以取值1。因此,我希望看到类似(1)
、(1 2 1 3)
、([1 2] [1 3])
甚至({:q 1 :a 2} {:q 1 :a 3})
的东西,但不是实际结果。
另一个例子:
(q/run* [q]
(q/fresh [a]
(q/membero a [1 2 3])
(q/membero q [3 4 5])
(q/== a q)))
;; make sense to me, returns (3)
(q/run* [q]
(q/fresh [a]
(q/membero a [1 2 3]))
(q/membero q [3 4 5]))
;; does not make sense to me, returns (3 4 3 5 4 3 5 4 5)
;; I was expecting `(3 4 5)`
有人能解释一下这里发生了什么吗?
core.logic可以被视为一种搜索算法,搜索为所有不会引起冲突的相关变量赋值的可能方法。它有很多非常聪明的修剪技术,这样它就不会搜索已知不好的子树,但基本上它是一个搜索。
它找到了两种方法来分配满足查询的变量:
- a=2,q=1
- a=3,q=1
所以它返回两个结果。但你只问q(这就是run*
的参数,你想知道的值的变量集),q在这两个赋值中都是一样的,所以你会看到两次相同的结果(1)。一般来说,你不应该假设run*
的结果是不同的,除非你已经付出了一些努力
同样,在上一个例子中,有三个值可以分配给q,每个值都适用于可以分配给a的三个值中的任何一个,因此您得到3*3=9个结果,每个q值重复三次。这些结果的返回顺序(从您的角度来看)是任意的;实际上,它们的排序方式有助于core.logic防止在其他更复杂的程序中出现死锁。如果您愿意,您可以通过编写(q/run* [a q] ...)
来查看所有的a、q对。