Prolog 确保规则的 return 参数是唯一的且按规范顺序排列
Prolog ensure a rule's return parameters are unique and in canonical order
我在 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).
请注意,数据没有为化合物 gen1(...)
定义 strong1
或 weak1
。这些是由对最小工作示例没有贡献的规则确定的。我提到它们是因为知道它们的存在可能会有用。
我试图找到这些形成循环的术语之间的关系。这是一个示例函数:
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).
此设置会删除 A
、B
和 C
顺序相同的重复项。但是,它不会删除不同顺序的重复项。例如:
?- 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.
该查询应该只 return 一组 [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 .
我也尝试了 <
和 >
,但显然它们对原子不起作用。
有什么想法吗?
(我看了类似的问题,但不知道我在这里做的和其他人做的相比如何)
编辑:根据关于最小工作示例的评论。
您可以尝试在 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).
我在 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).
请注意,数据没有为化合物 gen1(...)
定义 strong1
或 weak1
。这些是由对最小工作示例没有贡献的规则确定的。我提到它们是因为知道它们的存在可能会有用。
我试图找到这些形成循环的术语之间的关系。这是一个示例函数:
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).
此设置会删除 A
、B
和 C
顺序相同的重复项。但是,它不会删除不同顺序的重复项。例如:
?- 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.
该查询应该只 return 一组 [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 .
我也尝试了 <
和 >
,但显然它们对原子不起作用。
有什么想法吗?
(我看了类似的问题,但不知道我在这里做的和其他人做的相比如何)
编辑:根据关于最小工作示例的评论。
您可以尝试在 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).