Prolog 为什么';在添加冗余约束之前,此clpfd查询是否会终止?

Prolog 为什么';在添加冗余约束之前,此clpfd查询是否会终止?,prolog,clpfd,Prolog,Clpfd,我已经编写了一些谓词,它们采用列表的长度并对其附加了一些约束(这是正确使用的词汇表吗?) 第一个终止于此简单查询,但第二个不终止: ?- Small in 1..2, clp_length(Little, Small). Small = 1, Little = [_1348] ; Small = 2, Little = [_1348, _2174] ; false. ?- Small in 1..2, clp_length2(Little, Small). Small = 1, Little

我已经编写了一些谓词,它们采用列表的长度并对其附加了一些约束(这是正确使用的词汇表吗?)

第一个终止于此简单查询,但第二个不终止:

?- Small in 1..2, clp_length(Little, Small).
Small = 1,
Little = [_1348] ;
Small = 2,
Little = [_1348, _2174] ;
false.

?- Small in 1..2, clp_length2(Little, Small).
Small = 1,
Little = [_1346] ;
Small = 2,
Little = [_1346, _2046] ;
% OOPS %
这对我来说很奇怪,因为长度明显大于0。要解决这个问题,您可以搜索、找到零并推断从零开始相加只能增加数字,或者您可以向下传播1..2中的
约束。感觉额外的条款是多余的!这并不意味着我的clpfd心理模型是非常错误的

因此,我想我有两个问题(请回答第二个问题作为评论)

  • 具体来说,为什么这个附加约束会导致查询正常工作

  • 一般来说,我是否可以使用某个资源来了解clpfd是如何实现的,而不仅仅是查看如何使用它的一些示例?我不想读马库斯·特里斯卡的论文,但这是我能找到的唯一来源。如果我想回答这样的问题,这是我唯一的选择吗


    • 1mo,命名存在问题。请参阅之前的答案 以及推荐关系名称。你用不合适的名字是不会得逞的。因此,
      list_length/2
      list_fdlength/2
      将是一个合适的名称。因此,我们有
      列表长度/2
      列表长度2/2

      2DO,考虑<代码> ListFdTrnth2/2 < /代码>的规则。没有任何迹象表明0与您相关。因此,如果您使用0、1或-1或其他任何作为基本情况,则该规则将完全相同。那么,这个糟糕的规则怎么会意识到0是你的终结呢?更好的,考虑一个概括:

      list_fdlength2(fake(N), N) :- % Extension to permit fake lists N #< 0. list_fdlength2([], 0). list_fdlength2([_Head|Rest], Length) :- Length #= Length1 + 1, list_fdlength2(Rest, Length1). 也有假答案!多丑啊!至少,它们的数量是有限的。但是,如果使用
      Length#>=1
      代替
      Length#>=0
      。有了这个小小的改变,当N为非负时,就不再有任何虚假的解决方案,因此您的原始程序也会更好。

      相关:这个答案讨论了长度限制,并包含了一个指向实现的链接,它代替了
      小1..2
      而是
      小=1
      我不理解您的建议,如果我使用Small=1,它也无法终止<代码>列表长度fd(列表,1)
在生成第一个结果后不会终止。相同的冗余条款解决了这个问题,所以我仍然有相同的问题!这并不能回答我的问题,但我觉得它非常接近。你要说的是,Prolog会满足每个谓词的所有约束,谓词中的变量不会得到传入变量的约束?不,我不明白这将如何导致失败:
list\u lengthfd(list,1)
不会终止,除非我添加额外的子句。这是因为,即使我将文字1传递给它,它也不能知道1大于0?哦,我现在明白了。clpfd根本没有问题,这是因为
list\u lengthfd(\u0)
匹配这两个子句,而第二个子句直接导致无限递归,除非我明确禁止使用负数。 list_fdlength2(fake(N), N) :- % Extension to permit fake lists N #< 0. list_fdlength2([], 0). list_fdlength2([_Head|Rest], Length) :- Length #= Length1 + 1, list_fdlength2(Rest, Length1). ?- list_fdlength2(L, 1). L = [_A] ; L = [_A, _B|fake(-1)] ; L = [_A, _B, _C|fake(-2)] ; ... ?- list_fdlength2(L, 0). L = [] ; L = [_A|fake(-1)] ; L = [_A, _B|fake(-2)] ; ... list_fdlength(fake(N), N) :- N #< 0. list_fdlength([], 0). list_fdlength([_Head|Rest], Length) :- Length #>= 0, Length #= Length1 + 1, list_fdlength(Rest, Length1). ?- list_fdlength(L, 1). L = [_A] ; L = [_A, _B|fake(-1)] % totally unexpected ; false. ?- list_fdlength(L, 0). L = [] ; L = [_A|fake(-1)] % eek ; false.