The following Clojure code使用core.logic
以两个不同的顺序解决具有相同目标的相同逻辑问题。这种订购选择导致一个快速完成而另一个挂起。
(use `clojure.core.logic)
;; Runs quickly. Prints (1 2 3).
(clojure.pprint/pprint (run* [q] (fresh [x] (== x [1,2,3])
(membero q x))))
;; Hangs
(clojure.pprint/pprint (run* [q] (fresh [x] (membero q x)
(== x [1,2,3]))))
是否存在避免此问题的一般解决方案或常规做法?
答案 0 :(得分:8)
以下是我的理解:
使用core.logic
,您希望尽早缩短搜索空间。如果首先放置membero
约束,则运行将通过搜索membero
空间开始,并回溯==
约束产生的失败。但是membero
空间是巨大的,因为q
和x
都不统一或至少有限。
但是,如果您先放置==
约束,则直接将x
与[1 2 3]
统一起来,membero
的搜索空间现在明显受{ {1}}。
答案 1 :(得分:3)
如果您要使用membero
,则无法解决此问题。使用新变量调用membero
将导致它生成q
所属的所有(读取,无限)可能列表。当然,大于3的列表不适用 - 但是由于你使用了run*
,它将继续盲目地尝试大于计数3的列表,即使每个列表都会失败。
使用约束基础架构在较新版本的core.logic中编写更好的membero
版本是可能的,但有关人员如何做到这一点的详细信息可能会在未来几个月内发生变化。直到有一个坚实的公共API来定义约束,你才会遇到那些使Prolog陷入困境的微妙排序和非终止问题。