Prolog确保规则的返回参数是唯一的,并且按规范顺序

时间:2017-01-01 06:02:43

标签: prolog prolog-setof

我在Prolog文件中声明了一些如下所示的数据:

gen1(grass).
gen1(poison).
gen1(psychic).
gen1(bug).
gen1(rock).

...

gen1((poison, flying)).
gen1((ghost, poison)).
gen1((water, ice)).

...

weak1(grass, poison).
weak1(grass, bug).
weak1(poison, rock).

strong1(grass, rock).
strong1(poison, grass).
strong1(bug, grass).
strong1(poison, bug).
strong1(psychic, poison).
strong1(bug, poison).
strong1(bug, psychic).
strong1(rock, bug).

请注意,数据不会为化合物strong1定义weak1gen1(...)。这些是由对最小工作实例没有贡献的规则决定的。我提到它们是因为知道它们存在可能是有用的。

我试图找到形成一个循环的这些术语之间的关系。这是一个示例函数:

triangle1(A, B, C) :-
    setof(A-B-C, (
             gen1(A), gen1(B), gen1(C), A \= B, A \= C, B \= C,
              strong1(A, B), strong1(B, C), strong1(C, A)
             ), Tris),
    member(A-B-C, Tris).

此设置会删除重复项,其中ABC的顺序相同。但是,它不会删除不同顺序的重复项。例如:

?- triangle1(A, B, C),
   member(A, [bug, grass, rock]),
   member(B, [bug, rock, grass]),
   member(C, [bug, rock, grass]).
A = bug,
B = grass,
C = rock ;
A = grass,
B = rock,
C = bug ;
A = rock,
B = bug,
C = grass ;
false.

该查询应该只返回一组[A, B, C]

我已经考虑过使用sort/2,但有些情况下,简单的排序会改变答案的含义:

?- triangle1(A, B, C),
   sort([A, B, C], [D, E, F]),
   \+member([D, E, F], [[A, B, C], [B, C, A], [C, A, B]]).
A = D, D = bug,
B = F, F = psychic,
C = E, E = poison .

我也试过<>,但显然那些人不会对原子起作用。

有什么想法吗?

(我查看了类似的问题,但不知道我在这里做的事与其他人的做法相比如何)

编辑:根据关于最小工作示例的评论。

1 个答案:

答案 0 :(得分:2)

您可以尝试排序内部 setof/3来电。因此,您应该避免以错误的顺序生成三元组。

我的意思是:拨打setof/3,而不是

A \= B, A \= C, B \= C,

尝试

A @< B, A @< C, B \= C,

这样您强制A低于B且低于C,您可以避免重复并保持正确的解决方案。

完整triangle1/3

triangle1(A, B, C) :-
    setof(A-B-C, (
             gen1(A), gen1(B), gen1(C), A @< B, A @< C, B \= C,
              strong1(A, B), strong1(B, C), strong1(C, A)
             ), Tris),
    member(A-B-C, Tris).