5

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.

ailnlv
  • 1,779
  • 1
  • 15
  • 29
  • According to the facts in your DB, I think the second example should be Maps = [[[X,0], [Y,1]], [[X,1], [Y,1]]] – gusbro Jul 20 '11 at 13:45
  • you're right, I'll fix that right away. Sorry, I haven't slept much trying to solve this problem. – ailnlv Jul 20 '11 at 14:45

3 Answers3

3

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]]].
false
  • 10,264
  • 13
  • 101
  • 209
  • 1
    Thanks, this works, but you should replace the line that says `Answerp = Vars-Substs.` with `Pair = Vars-Substs.` – ailnlv Jul 20 '11 at 16:09
  • Thanks - that happens when one thinks while one types. @gusbro: `Answers` would be a list, but it is a pair. – false Jul 20 '11 at 16:58
2

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]]].
gusbro
  • 22,357
  • 35
  • 46
0

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.

DaveEdelstein
  • 1,256
  • 8
  • 14
  • I don't know if this is really necessary, but I need to do inner and left joins of sets of mappings (I'm basically parsing SPARQL patterns, but with arbitrary clauses instead of triples and using only "and" and "opt"). This solution almost works, but has the problem described by gusbro of not having the original variable names. It should also work with arbitrary clauses, not just binary ones with a known name. Thanks. – ailnlv Jul 20 '11 at 16:24