core.logic解释了`fresh`如何改变结果

时间:2017-01-11 17:02:06

标签: clojure logic clojure-core.logic

刚开始使用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。 并且q的值可以为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)`

有人能解释一下这里发生了什么吗?

1 个答案:

答案 0 :(得分:4)

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

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

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

所以它返回了两个结果。但是你只询问q(run*的参数是什么,你想要知道的变量集是什么),并且q在这两个赋值中是相同的,所以你看相同的结果(1)两次。你不应该一般认为run*的结果是不同的,除非你已经付出了一些努力来制作它们。

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