1
votes

I am trying to write a predicate in Prolog that will use my predicate 'PAR', which tests whether a 4 digit number meets certain conditions, but return a list of all numbers which are PARs, i.e. all numbers which return true when passed into par.

pars(A, C)
    :-  A =< 9999,
        par(A) -> append(C, A, C),
        A1 is A+1,
        pars(A1, C).

This is my current code, with A initially passed in as 1000 (the smallest 4 digit number), but it will only return false when the first number is tried, or timeout if the first number is a PAR.

I also want the predicate to take only one argument, e.g. pars(X) where X is then the list of PARs.

par(A)
    :-  number_chars(A, [W,X,Y,Z]),
        unique([W,X,Y,Z]),
        atom_number(W, W1),
        atom_number(X, X1),
        atom_number(Y, Y1),
        atom_number(Z, Z1),
        B1 is W1 * 10 + X1,
        B2 is Y1 * 10 + Z1,
        0 is mod(B1,B2).

Here is my par predicate for reference, I know this is also probably very inefficient.

Any help would be appreciated, thanks in advance.

1

1 Answers

2
votes

The easy way is to use a "solution-collecting" metapredicate, i.e. findall/3, bagof/3 or setof/3:

findall(P,(between(1000,9999,P),par(P)),Bag).

In this case the subgoal is between(1000,9999,P),par(P):

  • Generate a number P between 1000 and 9999
  • Test is for "par-ity"
  • If there is success of the above, it will be in the list Bag when findall/3 succeeds.
  • If there is failure of the above, the Prolog processor backtracks to the start of the subgoal and tries again, generating and testing the next number.

This can also be written more extensively (i.e. not "inlined"):

subgoal(P) :- between(1000,9999,P),par(P).

findthem(Bag) :- findall(P,subgoal(P),Bag).

(Testing this fails because I dont't have the definition of unique/1 as used in par/1.)