0

刚从core.logic版本“0.8.11”开始:

  (q/run* [q]
    (q/fresh [a]
      (q/membero a [2 3]))
    (q/membero q [1]))

我不明白结果:(1 1)

我的理解是我a用fresh创建了另一个变量,它可以取2或3q的值。并且可以取1。因此我期待看到类似的东西:(1), or (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)`

有人可以解释这里发生了什么吗?

4

1 回答 1

4

core.logic 可以被视为一种搜索算法,寻找可能的方法来为所有不会导致冲突的相关变量赋值。它有很多非常聪明的剪枝技术,因此它不会搜索已知不好的子树,但基本上它是一种搜索。

它找到了两种分配满足您查询的变量的方法:

  • a=2, q=1
  • a=3, q=1

所以它返回两个结果。但是您只询问 q (这就是参数run*是什么,您想知道其值的变量集),并且 q 在这两个分配中是相同的,所以您会看到相同的结果 (1) 两次。一般来说,你不应该假设结果run*会是不同的,除非你已经付出了一些努力来做到这一点。

同样,在您的上一个示例中,您可以分配三个值给 q,并且它们中的每一个都适用于您可以分配给 a 的三个值中的任何一个,因此您会得到 3*3=9 个结果,每个 q 值重复 3 次. 返回这些结果的顺序(从您的角度来看)是任意的;实际上,它们的排序方式有助于 core.logic 防止在其他更复杂的程序中陷入僵局。如果你愿意,你可以通过写来查看所有的 a,q 对(q/run* [a q] ...)

于 2017-01-11T18:27:35.803 回答