Getting list of solutions in Prolog
Asked Answered
P

2

11

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.
Psychoneurosis answered 16/11, 2010 at 3:44 Comment(0)
P
21

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].
Pehlevi answered 16/11, 2010 at 5:22 Comment(2)
findall, that's what I was trying to Google forGoodden
sharky, your findall implementation doesn't account for repeated elements. If you have this in the database: parent(hannah,carl). parent(hannah,carl). parent(bob,carl). your rule outputs [hannah,bob]. But if you try with findall you get [hannah,hannah,bob]Anacrusis
G
2

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)

Goodden answered 16/11, 2010 at 4:2 Comment(1)
I posted a follow up question to your answer regarding the "solutions" predicate: #47234486Assyrian

© 2022 - 2024 — McMap. All rights reserved.