关于在Prolog练习中使用CUT的一些问题

时间:2013-04-10 15:47:07

标签: prolog

我正在使用SWI Prolog学习Prolog进行大学考试,我对以下问题的两种不同解决方案之间的差异有一些疑问:

  

定义子句 count(X,L,NumX)其中X是原子,L是   list和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的特定点回溯。

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

第二个版本不会在第二个规则中执行此检查,但会在第一个规则中删除...

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

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

在计算和分支中采用不同的分支我没有N是N + 1?

1 个答案:

答案 0 :(得分:1)

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

第一个版本需要明确检查项目是否与列表头部不同,因为在回溯时,无论第二个子句是否成功,第三个子句都将被执行。

如果使用简单的1个元素的输入列表跟踪两个过程,您可以自己查看。

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

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

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

现在,您的程序的第二个版本(使用剪切的版本)。当prolog使用项目a进入第二个子句时,它会提交剪切,因此它不会留下选择点。现在你进行递归并以 Count = 1 的正确结果结束。

如果您现在要求prolog提供其他替代方案,它会说没有什么可以检查的。 由于削减,没有必要再检查A和B是否不同,因为您确定它们将是不同的,否则第二个子句将提交,第三个子句将不会被测试。