我开始研究一些微型看门人,并制作了该示例以计算列表中的1位。
(define (count xs n)
(conde
[(== xs '()) (== n 0)]
[(fresh (a b)
(== xs (cons a b))
(conde
[(== a 0) (count b n)]
[(== a 1) (count b (- n 1))]))]))
现在,以下方法可以正常工作
> (run* (q) (fresh (a b c) (== q (list a b c)) (count q 1)))
'((0 0 1) (1 0 0) (0 1 0))
但是如果我改变目标的顺序,程序不会终止
> (run* (q) (fresh (a b c) (count q 1) (== q (list a b c))))
. . user break
我已经不完全了解这一点,目标的顺序重要吗?用什么方式?我想我知道即使是随后的目标也可以构成足够的约束条件以终止搜索,但是我当然一定错过了一些事情。
进一步研究这个问题,我看到了
> (run 3 (q) (fresh (a b c) (count q 1) (== q (list a b c))))
'((0 0 1) (0 1 0) (1 0 0))
> (run 4 (q) (fresh (a b c) (count q 1) (== q (list a b c))))
. . user break
所以我知道它试图寻找比现有更多的答案。我现在的怀疑是,当子目标
(== xs (cons a b))
拆分列表,对b
的约束不足以使搜索变得有限,这听起来很合理,因为除了外部(== q (list a b c))
之外,没有其他人谈论列表的尾部。似乎期望非终止似乎更加合理,因为没有任何内容说明c
中的(== q (list a b c))
是什么,它可能是另一个列表(是真的吗?),但是该程序的交换版本如何终止?
我因此尝试了
(define (bit x)
(conde [(== x 0)] [(== x 1)]))
和
> (run 4 (q) (fresh (a b c) (bit a) (bit b) (bit c) (count q 1) (== q (list a b c))))
. . user break
但是它仍然没有终止,所以也许问题出在我想不到的地方。
总的来说,我的理解中肯定缺少一些东西,任何人都可以澄清所有这些并指出做这件事的正确方法吗?