ailnlv
ailnlv

Reputation: 1839

Find all solutions to a predicate

I'm trying to define a predicate that receives a single term with free variables and returns a list of mappings of those variables, so for example if the database is

a(0,1).
a(1,1).

the expected output would be

?- eval(a(X,1),Maps).
Maps = [[[X,0]],[[X,1]]].
?- eval(a(X,Y),Maps).
Maps = [[[X,0],[Y,1]],[[X,1],[Y,1]]].

I've been trying to accomplish this by using findall/3, but I can't figure out a way to ask for the free variables and their possible values. If it helps, I'm using swiprolog. Thanks.

Upvotes: 5

Views: 2299

Answers (3)

false
false

Reputation: 10102

Here is a solution to a similar problem. Instead of a list of answers represented as a list with entries [V,term] for each variable, the query goal_answers(Goal, Answerp) finds a pair Vars-Terms.

goal_answerp(Goal, Answerp) :-
   term_variables(Goal, Vars),
   findall(Vars, Goal, Substs),
   Answerp = Vars-Substs.

?- goal_answerp(a(X,1), Ms).
   Ms = [X]-[[0],[1]].
?- goal_answerp(a(X,Y), Ms).
   Ms = [X,Y]-[[0,1],[1,1]].

[Edit] To get the answers back in the original format use library(lambda):

?- goal_answerp(a(X,1), Vs-Dss),
         maplist(Vs+\Ds^VDs^maplist(\V^D^[V,D]^true,Vs,Ds,VDs),Dss,VDss).
   Vs = [X], Dss = [[0],[1]], VDss = [[[X,0]],[[X,1]]].
?- goal_answerp(a(X,Y), Vs-Dss),
         maplist(Vs+\Ds^VDs^maplist(\V^D^[V,D]^true,Vs,Ds,VDs),Dss,VDss).
   Vs = [X,Y], Dss = [[0,1],[1,1]], VDss = [[[X,0],[Y,1]],[[X,1],[Y,1]]].

Upvotes: 3

DaveEdelstein
DaveEdelstein

Reputation: 1256

I don't have an interpreter in front of me, but I imagine you could do this for this particular setup with your 'a' predicate.

var(X), 
var(Y), 
findall(U, 
  ( a(XSol,YSol), U=[[X,XSol], [Y,YSol]] ), 
  Maps).

(The var's might be unnecessary) I don't know why you'd want to do use this approach to any problem though...

Check out unifiable/3 for potentially a better way to do something like this.

Upvotes: 0

gusbro
gusbro

Reputation: 22585

There is an issue with what you want to do. The user-friendly name you give to the variables (e.g. X, Y) is known to the top level parser, but is "lost" inside your program. This snippet will list all the bindings but the variables will have generic names:

find_mappings(Template, Mappings):-
  term_variables(Template, Vars),
  find_mappings1(Vars, Mapping),
  findall(Mapping, Template, Mappings).

find_mappings1([], []).
find_mappings1([Var|Vars], [[Name,Var]|Mappings]):-
  term_to_atom(Var, Name),
  find_mappings1(Vars, Mappings).

?- find_mappings(a(X,Y), L).
L = [[['_G385', 0], ['_G386', 1]], [['_G385', 1], ['_G386', 1]]].

You might prefer to add another argument to your procedure to receive the proper names of your variables:

find_mappings(Template, Names, Mappings):-
  term_variables(Template, Vars),
  find_mappings1(Vars, Names, Mapping),
  findall(Mapping, Template, Mappings).

find_mappings1([], [], []).
find_mappings1([Var|Vars], [Name|Names], [[Name,Var]|Mappings]):-
  find_mappings1(Vars, Names, Mappings).

?- find_mappings(a(X,Y), ['X', 'Y'], L).
L = [[['X', 0], ['Y', 1]], [['X', 1], ['Y', 1]]].

Upvotes: 2

Related Questions