Let's start with a simpler problem: Given a list of variables and a list of ground values, assign those ground values to the variables. For example:
?- variables_values([X], [a, b, c]).
X = a ;
X = b ;
X = c.
This can be implemented like this:
variables_values([], _Values).
variables_values([Variable | Variables], Values) :-
member(Variable, Values),
variables_values(Variables, Values).
A bigger example:
?- variables_values([X, Y], [a, b, c]).
X = Y, Y = a ;
X = a,
Y = b ;
X = a,
Y = c ;
X = b,
Y = a ;
X = Y, Y = b ;
X = b,
Y = c ;
X = c,
Y = a ;
X = c,
Y = b ;
X = Y, Y = c.
The term_variables/2
predicate gives you a list of all the variables in a term. You can combine this with the above predicate:
?- Pattern = predicate(X, Y), term_variables(Pattern, Variables), variables_values(Variables, [a, b, c]).
Pattern = predicate(a, a),
X = Y, Y = a,
Variables = [a, a] ;
Pattern = predicate(a, b),
X = a,
Y = b,
Variables = [a, b] ;
Pattern = predicate(a, c),
X = a,
Y = c,
Variables = [a, c] ;
Pattern = predicate(b, a),
X = b,
Y = a,
Variables = [b, a] . % etc.
Note that instantiating the variables in the list also instantiates them in the pattern -- the variables are shared.
Given this, the last piece of the puzzle is a predicate that computes a list of instantiations of a pattern, given some predicate that instantiates variables. findall/3
is the right tool for this job:
pattern_values_grounded(Pattern, Values, Grounded) :-
term_variables(Pattern, Variables),
findall(Pattern, variables_values(Variables, Values), Grounded).
This does what you seem to want:
?- pattern_values_grounded(predicate(X), [a, b, c], Grounded).
Grounded = [predicate(a), predicate(b), predicate(c)].
?- pattern_values_grounded(predicate(X, Y), [a, b, c], Grounded).
Grounded = [predicate(a, a), predicate(a, b), predicate(a, c), predicate(b, a), predicate(b, b), predicate(b, c), predicate(c, a), predicate(c, b), predicate(..., ...)].