Prolog与回溯的局限性

Prolog与回溯的局限性,prolog,Prolog,这可能是在Prolog中返回列表长度的函数的最简单的实现 count([], 0). count([_|B], T) :- count(B, U), T is U + 1. 关于Prolog,我仍然无法理解的一点是使用变量作为参数的灵活性 例如,我可以运行count([a,b,c],3)。并获得true。我还可以运行count([a,b],X)。并获得答案X=2。。奇怪的是(至少对我来说)我还可以运行count(X,3)。并至少得到一个结果,看起来像X=[\uG4337877,\uG43378

这可能是在Prolog中返回列表长度的函数的最简单的实现

count([], 0).
count([_|B], T) :- count(B, U), T is U + 1.
关于Prolog,我仍然无法理解的一点是使用变量作为参数的灵活性

例如,我可以运行
count([a,b,c],3)。
并获得
true
。我还可以运行
count([a,b],X)。
并获得答案
X=2。
。奇怪的是(至少对我来说)我还可以运行
count(X,3)。
并至少得到一个结果,看起来像
X=[\uG4337877,\uG4337880,\uG4337883]count(X,A)。
并获得
X=[],A=0;X=[[u G4369400],A=1.
,这显然是不完整的,但不知怎么的,确实很好

因此,我的问题是多方面的。我是否可以向Prolog解释一下,在执行计数(X,3)时不要超出第一个结果的范围。
?我可以让Prolog为计数(X,A)生成任意数量的解决方案吗?我能产生什么样的解决方案有限制吗?这个特定谓词是什么阻止我为所有可能的查询生成所有解决方案的

这可能是最简单的实现

从观点看:考虑

count(L,C) :- length(L,C).
短而实用。这个也适用于您的用例

编辑

图书馆允许

:- use_module(library(clpfd)).

count([], 0).
count([_|B], T) :- U #>= 0, T #= U + 1, count(B, U).

?- count(X,3).
X = [_G2327, _G2498, _G2669] ;
false.
(进一步)答复评论

这显然是讽刺

不,很抱歉给你留下这样的印象。这是对你的问题的综合回答。length/2实现的每一个细节——确实比您的代码长得多——都经过了仔细的权衡,为我们提供了一个通用而高效的构建块

一定有一些一般的概念

我把(完整的)序言称为这样的一般概念。从一开始,Prolog就要求我们解决描述谓词参数之间关系的计算任务。一旦我们描述了我们之间的关系,我们就可以查询我们的“知识数据库”,Prolog将尝试按特定顺序列举所有答案

和(回溯)等高级概念是该模型中的关键

现在,我认为您正在寻找像/1这样的二阶结构,它允许我们对谓词进行推理。这样的结构不能用(纯)Prolog编写,越来越多的人需要避免它们,因为它们很难使用。所以我发布了一个使用CLP(FD)的替代方案,它在某些情况下有效地保护了我们。在这个特定于问题的上下文中,它实际上为我们提供了一个简单而优雅的解决方案

我并没有试图重新实现长度


我知道这一点,但既然count/2别名长度/2,为什么不研究参考模型呢?(请参见SWI Prolog网站)

查询
计数(X,3)
得到的答案实际上一点也不奇怪。您正在询问哪些列表的长度为3。你会得到一个包含3个元素的列表。出现无限循环是因为递归规则的第一个目标中的变量B和U未绑定。在实现目标之前,你没有任何可能失败的东西。因此,始终可以遵循递归。在Capelical的版本中,在递归之前的第二条规则中有2个目标,如果第二个参数小于1,则会失败。如果你考虑这个稍微改变的版本:
:- use_module(library(clpfd)).

count([], 0).
count([_|B], T) :-
    T #> 0,
    U #= T - 1,
    count(B, U).
你的问题

?- count(X,3).
将不匹配第一个规则而匹配第二个规则,并递归继续,直到第二个参数为0。此时,第一条规则将匹配并产生结果:

X = [_A,_B,_C] ?
第二条规则的头也将匹配,但其第一个目标将失败,因为
T=0

X = [_A,_B,_C] ? ;
no

然而,在您上面的版本中,Prolog将尝试第二条规则的递归目标,因为未绑定变量B和U,因此会无限循环。

@vasily:这真的是您想要的答案吗?@Capelical,对不起,但这对我来说非常神秘。我并不是在试图重新实现长度,我是在试图理解为什么我的原始的蓝眼睛实现失败了,是什么让我的实现变得“不完整”。一定有一些一般性的概念描述了我在这里要讨论的内容。@capelical,谢谢你的解释和到纯度主题的链接。事实上,这一问题与我所问的问题非常相关:@vasily:我说这话时没有任何讽刺或讽刺:老实说,这是我在stackoverflow上看到的关于Prolog的最快学习曲线之一+感谢Capelical和@tas的观察和高度合理的问题及深刻的回答!第一阶:参数的变量。第二级:谓词的变量
var/1
就像你说的那样:元逻辑在没有clpfd的情况下也可以工作,不是吗?计数([],0)。count([|B],T):-T>0,U是T-1,count(B,U)。@Bezewy:不,尝试最通用的查询
?-count(List,Len)。
它会在回溯时崩溃,应该枚举所有解决方案,就像CLP(FD)版本一样。