关于这段序言锻炼
我使用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是否有所不同,因为您确定它们会不同,否则第二个条款将提交并且第三个条款不会被测试。
好吧,现在对我来说更加清楚......最后一个问题是:在程序的第二个版本中(使用剪切),规则的顺序很重要,是对的吗? – AndreaNobili 2013-04-11 16:29:17
@AndreaNobili:是的,这很重要。如果你交换最后两个子句,你会得到不正确的结果(也是正确的)。 – gusbro 2013-04-11 16:49:41