自定义子集不回溯

时间:2016-11-01 13:20:49

标签: prolog subset

我是初学者,我一直在做一些功课。 在我的代码的某些部分,我必须在回溯上生成给定集合的子集。意思是,代码应该尝试子集,当它在下一个条件失败时,尝试下一个子集。我做了一些研究,默认函数subset不会回溯,因为正如this中所解释的那样,两个参数都是input arguments。所以我建立了一个自定义的,仍然没有回溯。你能告诉我一些我失败的事吗?这是我的代码:

    numNutrients(8).
    product(milk,[2,4,6]).
    product(porkChops,[1,8]).
    product(yoghurt,[3,1]).
    product(honey,[5,7]).
    product(plastic,[3,5,2]).
    product(magic,[5,7,8]).

nutrientlist(N,L):-findall(I,between(1,N,I),L). subset2([],[]):-!. subset2([X|T],[X|T2]):- subset2(T,T2). subset2([_|T],[T2]):- subset2(T,T2). shopping(K,L):- numNutrients(J), nutrientlist(J,N), findall(P,product(P,_),Z), subset2(X,Z), length(X,T), T =< K, covers(X,N), L = X. covers(_,[]):-!. covers([X|L],N):- product(X,M), subset2(M,N), subtract(N,M,T), covers(L,T). main:- shopping(5,L), write(L).

问题在于谓词购物(K,L)。当它到达谓词subset2时,它给出整个集合,其长度为6(不是5),然后失败并且不回溯。由于所有先前的谓词都无法回溯,因此失败了。

那么,为什么不对subset2进行回溯?

感谢您的时间。

1 个答案:

答案 0 :(得分:1)

主要焦点:subset2/2

首先,让我们将集中在谓词上,该谓词显示与您期望的属性不同的属性。

在您的情况下,这只是 subset2/2,由您定义为:

subset2([], []) :- !.
subset2([X|T], [X|T2]) :-
        subset2(T, T2).
subset2([_|T], [T2]) :-
        subset2(T, T2).

我现在将使用声明性调试来查找问题的原因。

要应用此方法,我删除!/0 ,因为声明性调试最适用于单调逻辑程序。有关详细信息,请参阅。因此,我们将继续努力:

subset2([], []).
subset2([X|T], [X|T2]) :-
        subset2(T, T2).
subset2([_|T], [T2]) :-
        subset2(T, T2).

测试用例

让我们首先构建一个产生非预期答案的测试用例。例如:

?- subset2([a], [a,b]).
false.

显然意图。我们可以概括测试用例吗?是:

?- subset2([a], [a,b|_]).
false.

所以,我们现在有一个无限的例子系列产生错误的结果。

练习:是否还存在程序过于笼统的情况,即成功的测试用例,尽管它们会失败?

找出错误

为什么我们在上述案例中看到了意外失败?要找出这些错误,让我们概括该程序。

例如:

subset2(_, []).
subset2([_|T], [_|T2]) :-
        subset2(T, T2).
subset2(_, [T2]) :-
        subset2(T, T2).

即使有大量概括,我们仍然

?- subset2([a], [a,b|_]).
false.

也就是说,我们在很多情况下期望查询成功,但失败。这意味着剩下的程序,即使它是原始程序的大量泛化,仍然太具体

更正程序

要使显示的案例成功,我们必须

  • 添加条款,描述我们需要的案例
  • 更改现有条款涵盖这些案例

例如,一个出路就是以下子句添加到数据库中:

subset2([a], [a,b|_]).

我们甚至可以概括为:

subset2([a], [a|_]).

将这些子句中的任何一个或两个添加到程序中将使查询成功:

?- subset2([a], [a,b|_]).
true.

然而,这当然是我们正在寻找的subset2/2的一般定义,因为例如在以下情况下仍会失败:

?- subset2([x], [x,y|_]).
false.

因此,让我们使用其他选项,并更正现有定义。特别是,让我们考虑一般化程序的最后一个条款:

subset2(_, [T2]) :-
        subset2(T, T2).

请注意,如果第二个参数是恰好一个元素的列表,则该成立,该列表受进一步约束的约束。这似乎太具体了

因此,我建议您首先更改此子句,以便至少使得到目前为止收集的测试用例成功。然后,添加必要的特化,使其成功成功用于预期的案例。