When you try to define a predicate in Prolog, first of all pretend that you have written that predicate already and start with imagining how you would use it. That is, what queries you would like to pose.
To me, it looks as if coexist/2
already describes what you want. BTW, may_coexist/2
might be a more descriptive name. Why do you want this in a separate list? And why using fruit/3
at all? But for the sake of the question let's assume that this makes sense. So essentially you would have now a relation fruit_compatible/2
:
fruit_compatible(F, G) :-
fruit(F, _, _),
may_coexist(F, G),
fruit(G, _, _). % maybe you want to add this?
And now, let's assume you want this list too. So you would have a relation fruit_suggestions/2
. How to use it?
?- fruit_suggestions(apple, L).
L = [cherry,pear].
or ... should it be rather L = [pear,cherry]
? Or both?
?- fruit_suggestions(lemon, L).
L = [orange].
So every time I want a suggestion I have to think of a fruit. Always thinking: what fruit should it be? Fortunately there is a less demanding way in Prolog: Simply use a variable instead of the fruit! Now we should get all suggestions at once!
?- fruit_suggestions(F, L).
F = apple, L = [cherry, pear]
; F = lemon, L = [orange]
; F = cromulon, L = [embiggy, mushfruit].
So we need to implement it such that it will behave that way. findall/3
alone does not solve this. And implementing it manually is far from trivial. But there is setof/3
which handles variables in exactly that manner. Many of the tiny nitty-gritty design decisions have already been made, like that the list will be sorted ascendingly.
fruit_suggestions(F, L) :-
setof(G, fruit_compatible(F, G), L).
Edit: Due to the discussion below, here would be a solution that also permits empty lists. Note that this sounds trivial but it is not. To see this, consider the query:
?- fruit_suggestions(F, []).
What does it mean? What should F
be? Also things that are no fruits at all? In that case we would have to produce solutions for everything. Like F = badger ; F = 42 ; ...
. Most probably this does not make much sense. What might be intended is those fruits that are incompatible with everything. To this end, we need to add a new rule:
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).