如何用Prolog正确地写出暗示?(How to correctly write an implication in implication with prolog?)

我正在尝试编写一个谓词,只有当列表D包含列表A中的元素时,才会成立,这些元素在列表A中的次数。例如 -

D [1,5,5,3]; A [4,6,1,0,5,3,5]

将是真的

D [1,5,5,3]; A [4,6,1,0,5,3,5,5]

将是假的,因为D只有5次,但A有5次。 我试图这样做有意义。 我的代码片段就像以下一样 -

sub_third(_, []) :- true. sub_third(D, [H|T]) :- member(H, D) -> select(H, D, D_new), sub_third(D_new, T) ; false. third(_, [], _) :- true. third(D, [H|T], A) :- (\+member(H, D) -> select(H, A, A_new), third(D, T, A_new) ; third(D, T, A)) -> (sub_third(D, A_new); false).

基本上我在这里做的是传递'第三个'谓词列表D和两个列表A.第一个实现我试图删除第二个A列表中的所有元素,这些元素在第一个A列表中找不到(如果H元素存在在列表D中,然后使用下一个T元素递归调用该调用并且不进行任何更改,但是如果在D列表中找不到H,则将其从第二个A列表中删除并再次调用递归,但是使用修改后的A列表)。 当没有更多的T元素时,列表A应该只包含与列表D相同的元素,然后使用sub_third谓词找出,如果所有元素都是相同的计数。 Sub_third工作正常,所以我认为错误应该在影响范围内,因为我不熟悉它们。

PS成员函数检查元素是否是列表的成员,并且select函数接受元素和列表,然后从第一个列表中删除给定元素的第三个列表。 (这就是我在这里使用它的方式)

I am trying to write a predicate, that will be true if and only then if list D contains elements from list A, the number of times those elements are in list A. For example -

D[1, 5, 5, 3]; A[4, 6, 1, 0, 5, 3, 5]

will be true

D[1, 5, 5, 3]; A[4, 6, 1, 0, 5, 3, 5, 5]

will be false, because D has 5 only two times, but A has 5 three times. And I am trying to do this with implications. My code snippet is as fallows-

sub_third(_, []) :- true. sub_third(D, [H|T]) :- member(H, D) -> select(H, D, D_new), sub_third(D_new, T) ; false. third(_, [], _) :- true. third(D, [H|T], A) :- (\+member(H, D) -> select(H, A, A_new), third(D, T, A_new) ; third(D, T, A)) -> (sub_third(D, A_new); false).

Basically what I am doing here is passing the 'third' predicate list D and twice list A. With first implementation I am trying to remove all the elements from second A list, that are not found in the first A list (if H element exist in list D, then call the call recursive with next T elements and make no changes, but if H is not found in D list, then remove it from second A list and call recursive again, but with modified A list). When there are no more T elements, list A should contain only the same elements as list D and then with sub_third predicate find out, if all the elements are the same count. Sub_third works fine, so I think that mistake should be somewhere within the implications since I am not that familiar with them.

P.S. member function checks if element is a member of a list and select function takes in an element and list, then makes third list from the first list with removed given element. (that's how I used it here)

最满意答案

您应该尝试为谓词找到更清晰的名称。 即使你知道sub_third应该是什么意思,我们也不知道。 这使得理解和调整代码变得更加困难。

你使用select/3基本想法是好的,但你还没有正确地分解问题。 首先尝试计算列表之间的差异,然后检查它不包含任何不需要的元素的额外属性:

% list_subtract(Xs, Ys, Zs) is true if Zs is a list obtained by removing one % occurrence of each element of Ys from Zs. False if there are elements in % Ys that have no corresponding occurrence in Xs. list_subtract(Xs, [], Xs). list_subtract(Xs, [Y|Ys], Zs) :- select(Y, Xs, Xs1), list_subtract(Xs1, Ys, Zs). % tests :- list_subtract([4, 6, 1, 0, 5, 3, 5], [1, 5, 5, 3], Zs), Zs = [4, 6, 0]. :- list_subtract([4, 6, 1, 0, 5, 3, 5, 5], [1, 5, 5, 3], Zs), Zs = [4, 6, 0, 5]. % list_subtract_without_rest(Xs, Ys, Zs) is true if Ys can be subtracted % from Xs in the sense of the list_subtract/3 predicate, and the remaining % difference Zs does not contain any elements of Ys. list_subtract_without_rest(Xs, Ys, Zs) :- list_subtract(Xs, Ys, Zs), \+ (member(Z, Zs), member(Z, Ys)). % tests :- list_subtract_without_rest([4, 6, 1, 0, 5, 3, 5], [1, 5, 5, 3], _). :- \+ list_subtract_without_rest([4, 6, 1, 0, 5, 3, 5, 5], [1, 5, 5, 3], _).

You should try to find clearer names for your predicates. Even if you know what sub_third is supposed to mean, we don't. That makes it harder to understand and adapt your code.

Your basic idea of using select/3 is good, but you have not decomposed the problem properly. Try computing the difference between your lists first, and then checking the extra property that it does not contain any unwanted elements:

% list_subtract(Xs, Ys, Zs) is true if Zs is a list obtained by removing one % occurrence of each element of Ys from Zs. False if there are elements in % Ys that have no corresponding occurrence in Xs. list_subtract(Xs, [], Xs). list_subtract(Xs, [Y|Ys], Zs) :- select(Y, Xs, Xs1), list_subtract(Xs1, Ys, Zs). % tests :- list_subtract([4, 6, 1, 0, 5, 3, 5], [1, 5, 5, 3], Zs), Zs = [4, 6, 0]. :- list_subtract([4, 6, 1, 0, 5, 3, 5, 5], [1, 5, 5, 3], Zs), Zs = [4, 6, 0, 5]. % list_subtract_without_rest(Xs, Ys, Zs) is true if Ys can be subtracted % from Xs in the sense of the list_subtract/3 predicate, and the remaining % difference Zs does not contain any elements of Ys. list_subtract_without_rest(Xs, Ys, Zs) :- list_subtract(Xs, Ys, Zs), \+ (member(Z, Zs), member(Z, Ys)). % tests :- list_subtract_without_rest([4, 6, 1, 0, 5, 3, 5], [1, 5, 5, 3], _). :- \+ list_subtract_without_rest([4, 6, 1, 0, 5, 3, 5, 5], [1, 5, 5, 3], _).

更多推荐