I am learning prolog and I am reading a book called Programming Prolog for Artificial Intelligence. As practice I want to learn how to extend one of the examples in this book. Can someone please help?
Say you have these facts:
parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob
How would I write a prolog predicate that would give me a list of bobs parents? For example:
list_parents(bob, L).
L = [pam, george] ;
L = [george, pam] ;
true.
An all-solutions predicate like findall/3
might do the trick:
list_parents(P, L) :-
findall(Parent, parent(Parent, P), L).
Simply put, findall/3
finds all bindings for Parent
in the 'backtrack-able' goal parent(Parent, P)
, and puts all bindings of Parent
into the list L
. Note that this won't remove duplicates, but you can do a sort/2
to L
before returning it to create a set. Executing this:
?- list_parents(bob, L).
L = [pam, george].
If you don't have findall/3
in your PROLOG implementation, you could do it manually like this:
list_parents(P, L) :-
list_parents(P, [], L).
list_parents(P, Acc, L) :-
parent(Parent, P),
\+ member(Parent, Acc), !,
list_parents(P, [Parent|Acc], L).
list_parents(_, L, L).
This version sends calls to list_parents/2
off to an accumulator-version, list_parents/3
. The latter tries to collect Parent
bindings also, as long as we haven't seen them before (hence the \+ member
check), and returns the list where no new Parent
bindings accumulated into the Acc
list can be found. Executing this gives us the same result as the first option:
?- list_parents(bob, L).
L = [pam, george].
Try this:
parent(pam, bob). %pam is a parent of bob
parent(george, bob). %george is a parent of bob
list_parents(A, Es, [X|Xs]) :- parent(X, A), \+ member(X, Es), list_parents(A, [X|Es], Xs).
list_parents(A, Es, []).
That was an inefficient method, a better method will need a "solutions" higher-order predicate.
list_parents(X, Ys) :- solutions(parent, [X, W], 1, Ys)