关于这段序言锻炼

问题描述:

我使用SWI Prolog的学习Prolog的一个大学考试,我对之间的下列问题的两种不同解决方案的差异有些疑惑使用CUT中的一些问题:关于这段序言锻炼

定义条款计数(X,L,NumX)其中X是原子,L是 列表和NumX是出现的次数即X出现在L.

这是第一个解决方案:

count0(_,[],0). 

count0(A, [A|Tail], N) :- 
      count0(A,Tail,N1), % L'elemento cercato appare N1 volte nella sottolista 
       N is N1+1.  % N vale N1+1 

count0(A, [B|Tail], N) :- 
      A\=B,   % A è diverso da B 
     count0(A,Tail,N). % N è il numero di occorrenze di A nella sottolista 

这是第二个解决方案:

count1(_,[],0). 

count1(A, [A|Tail], N) :- !, 
         count1(A, Tail, N1), 
       N is N1+1. 

count1(A, [_|Tail], N) :- count1(A, Tail, N). 

我的问题是,我不理解它扮演的角色在第二版的CUT

我知道CUT防止回溯在CUT被放置的特定点。

该程序的第一个版本检查A是否与第二条规则中的B不同(我需要这个?如果第一条规则失败了,所以这意味着A不与该头的头部统一该列表的头是从A处的元素)

第二个版本不执行此检查在第二个规则,但把削减的第一条规则不同...

这可能取决于由事实上(在第二个版本中)如果我不阻止回溯,那么:在此之后,如果我强制使用回溯,Prolog给我第一个(正确)回应;碰巧使用第二条规则:

count1(A, [_|Tail], N) :- count1(A, Tail, N). 

采取了不同的分支在计算和该分支我没有N是N + 1?

第一个版本在第二个子句中留下选择点,而第二个版本在它进入第二个子句时对该子句进行提交(与剪切)。

第一个版本需要明确检查项目是因为,在回溯从列表的头部不同,第三子句,将忽略第二条款是否成功之前执行。

如果您使用简单的输入列表说明1元素跟踪两个过程,您可以亲自看到它。

?- count0(a,[a], Count). 

你的程序将项目与列表的匹配,并执行递归的第一个版本。然而,如果需要,它将在那里留下选择的位置以查看其他替代方案。 然后递归因为基本情况(空列表)而结束,并且您得到Count = 1的结果。

如果您现在要求prolog其他选择,它仍然有该选择点,所以它会尝试thirc子句。如果你没有明确地检查A和B是否不同,它会递归地调用它自己(再次使用空列表)并返回Count = 0这是一个错误的答案!

现在,您的程序的第二个版本(使用剪切的那个版本)。当prolog用第一个项目输入第二个子句时,它会提交切割,所以它不会离开选择点。现在您进行递归并以Count = 1的正确结果结束。

如果你现在要求prolog其他选择,它会说没有什么可以检查。 由于削减的结果,没有必要检查A和B是否有所不同,因为您确定它们会不同,否则第二个条款将提交并且第三个条款不会被测试。

+0

好吧,现在对我来说更加清楚......最后一个问题是:在程序的第二个版本中(使用剪切),规则的顺序很重要,是对的吗? – AndreaNobili 2013-04-11 16:29:17

+1

@AndreaNobili:是的,这很重要。如果你交换最后两个子句,你会得到不正确的结果(也是正确的)。 – gusbro 2013-04-11 16:49:41