Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 970
ailnlv Avatar asked Jul 20 '11 12:07

ailnlv


2 Answers

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]]].
like image 100
false Avatar answered Oct 11 '22 20:10

false


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]]].
like image 44
gusbro Avatar answered Oct 11 '22 20:10

gusbro