当您尝试在 Prolog 中定义谓词时,首先假装您已经编写了该谓词并开始想象您将如何使用它。也就是说,您想提出什么问题。
在我看来,coexist/2 似乎已经描述了你想要什么。顺便说一句,may_coexist/2 可能是一个更具描述性的名称。为什么要将它放在单独的列表中?为什么要使用fruit/3?但是为了这个问题,让我们假设这是有道理的。所以基本上你现在有一个关系fruit_compatible/2:
fruit_compatible(F, G) :-
fruit(F, _, _),
may_coexist(F, G),
fruit(G, _, _). % maybe you want to add this?
现在,假设您也想要这个列表。所以你会有一个关系fruit_suggestions/2。怎么用?
?- fruit_suggestions(apple, L).
L = [cherry, pear].
或者...应该是L = [pear, cherry]?还是两者兼有?
?- fruit_suggestions(lemon, L).
L = [orange].
所以每次我想要一个建议时,我都必须想一个水果。一直在想:应该是什么水果?幸运的是,Prolog 中有一种要求不高的方法:只需使用变量而不是水果!现在我们应该立即获得所有建议!
?- fruit_suggestions(F, L).
F = apple, L = [cherry, pear] ;
F = lemon, L = [orange] ;
F = cromulon, L = [embiggy, mushfruit].
所以我们需要实现它,使它的行为方式。 findall/3 单独不能解决这个问题。手动实现它绝非易事。但是有setof/3 以这种方式处理变量。许多微小的细节设计决策已经做出,例如列表将按升序排序。
fruit_suggestions(F, L) :-
setof(G, fruit_compatible(F, G), L).
编辑:由于下面的讨论,这将是一个也允许空列表的解决方案。请注意,这听起来微不足道,但事实并非如此。要看到这一点,请考虑以下查询:
?- fruit_suggestions(F, []).
这是什么意思? F 应该是什么?还有那些根本不是水果的东西?在这种情况下,我们将不得不为一切提供解决方案。喜欢F = badger ; F = 42 ; ...。很可能这没有多大意义。可能是那些与一切不相容的果实。为此,我们需要添加一条新规则:
fruit_suggestions(F, []) :-
setof(t,X^Y^fruit(F,X,Y),_),
\+ fruit_compatible(F, _).
fruit_suggestions(F, L) :-
setof(G, fruit_compatible(F, G), L).