Search code examples
prologprolog-findall

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.


Solution

  • 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]]].