This is probably something that people have needed to solve before.
Yes, indeed.
How do I solve this elegantly?
I would use Prolog, because it fits perfectly in this case.
Prolog predicates are made of different clauses; let's define
the x/1 predicate (x/1 means functor x with arity 1) :
x(-1).
x(0).
x(1).
Then, any call to x(V) with V a free variable will leave "choice points" that are visited upon backtrack. Interactively:
[eclipse]: x(V).
V = -1
Yes (0.00s cpu, solution 1, maybe more) ? ;
V = 0
Yes (0.00s cpu, solution 2, maybe more) ? ;
V = 1
Yes (0.00s cpu, solution 3)
We do not necessarily need to have two clauses, though:
y(Y) :- Y = "hello"; Y = "goodbye".
Here, the ; disjunction operator separates two alternative unifications of variable V with different strings.
Let's define also a z/1 predicate, using the between/4 built-in auxiliary predicate :
z(Result) :- between(0,100,1,Result).
Now, you will need to call a specific test function, which depends heavily on your exact requirements. But here is a sketch of how to call it:
run :-
x(X),
y(Y),
z(Z),
test(X,Y,Z),
% failing here will backtrack over other values of X, Y, Z.
fail.
% since the previous clause of the run predicate always fail, we
% add another one that will succeed. It will be tried after all values of
% X, Y and Z have been attempted. Since there is no need to have a body, we
% simply write "run."
run.
The test/3 predicate is where you should define your test. You might want to concatenate all your terms and call an external shell, for example:
test(X,Y,Z) :-
join_string(["./test",X,Y,Z]," ",Cmd),
sh(Cmd).
Alernatively, you can talk to another process with sockets or through a stream. This particular example does not handle possible spaces in arguments, so take care.
It isn't python or any other popular scripting language, but I think it is worth trying. After all, if it fails, you can just got back trying another option :-)