Get unique results with Prolog

独自空忆成欢 提交于 2020-01-05 10:28:14

问题


I have this Prolog code that returns: [[vincent,vincent],[vincent,marcellus],[marcellus,vincent],[marcellus,marcellus],[pumpkin,pumpkin],[honey_bunny,honey_bunny]].

:- initialization main.

loves(vincent, mia).
loves(marcellus, mia).
loves(pumpkin, honey_bunny).
loves(honey_bunny, pumpkin).

jealous(X, Y) :-
    loves(X, Z),
    loves(Y, Z).

main :- 
    findall([X, Y], jealous(X, Y), L),
    write(L),
    halt.

How to get the only results when X != Y? I tried the following code to get the same results as before.

jealous(X, Y) :-
    X \== Y,
    loves(X, Z),
    loves(Y, Z).

With \=, I got []. How to get only [vincent,marcellus] as a result?


回答1:


The order of the goals in your attempted solution is wrong. When called with two distinct variables, the (\==)/2 standard predicate always succeed. The solution is to call the predicate only when its arguments are instantiated:

jealous(X, Y) :-
    loves(X, Z),
    loves(Y, Z),
    X \== Y.

With this fix, your query now returns:

?- findall([X, Y], jealous(X, Y), L).
L = [[vincent, marcellus], [marcellus, vincent]].

So, no one is jealous of himself anymore. But you still get a redundant solution. We can modify the jealous/2 predicate to sort the names in the returned solutions. For example:

jealous(X, Y) :-
    loves(X0, Z),
    loves(Y0, Z),
    X0 \== Y0,
    (   X0 @< Y0 ->
        X = X0, Y = Y0
    ;   X = Y0, Y = X0
    ).

Now, by using setof/3 instead of findall/3, we get:

?- setof([X, Y], jealous(X, Y), L).
L = [[marcellus, vincent]].

One final observation. A list is a poor solution for representing a pair. The traditional way is to use either X-Y or (X, Y).




回答2:


Whenever possible, use dif/2 instead of (\==)/2.

dif/2 will help you write logically sound programs.

For details, look at prolog-dif!



来源:https://stackoverflow.com/questions/28267488/get-unique-results-with-prolog

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!