I would probably use a combination of CLP (FD) and DCG, since we are dealing with sequences.
Here's an implementation that recognizes sequences containing exactly one 3 or one 4:
:- use_module(library(clpfd)). one_of_3_4 --> no_3_4, [3], no_3_4. one_of_3_4 --> no_3_4, [4], no_3_4. no_3_4 --> []. no_3_4 --> [X], { X in 1..2 \/ 5..9 }.
This gives something like this:
2 ?- phrase(one_of_3_4, L), label(L). L = [3] ; L = [3, 1] ; L = [3, 2] ; L = [3, 5] ; L = [3, 6] ; L = [3, 7] ; L = [3, 8] ; L = [3, 9] ; L = [1, 3] ; L = [2, 3] ; L = [5, 3] ; L = [6, 3] ; L = [7, 3] ; L = [8, 3] ; L = [9, 3] ; ...
This is not a complete solution to the original problem, but should give an idea of how to approach it in a transparent way.
<h / "> If you do not want to use DCG, here is another approach that first indicates a list of single digits other than 3 or 4, then inserts 3 or 4 anywhere in the list (SWI Prolog):
:- use_module(library(clpfd)). one_of_3_4(L) :- length(L1, _), L1 ins 1..2 \/ 5..9, ( select(3, L, L1) ; select(4, L, L1) ).
Then it can be called as follows:
2 ?- one_of_34(L), label(L). L = [3] ; L = [4] ; L = [3, 1] ; L = [3, 2] ; L = [3, 5] ; L = [3, 6] ; L = [3, 7] ; L = [3, 8] ; L = [3, 9] ; L = [1, 3] ; L = [2, 3] ; L = [5, 3] ; L = [6, 3] ; L = [7, 3] ; L = [8, 3] ; L = [9, 3] ; L = [4, 1] ; L = [4, 2] ; L = [4, 5] ; L = [4, 6] ; L = [4, 7] ; L = [4, 8] ; L = [4, 9] ; L = [1, 4] ; L = [2, 4] ; L = [5, 4] ; L = [6, 4] ; L = [7, 4] ; L = [8, 4] ; L = [9, 4] ; ...
<h / "> In response to the comments on this answer, you can create a non-member predicate that applies specifically to the CLP (FD) script:
not_member(_, []). not_member(X, [Y|T]) :- X
Or, in short, you can shorten not_member/2 with maplist/2 as:
not_member(X, L) :- maplist(
Using not_member/2 , this will work as expected:
mutual(Output, A, B):- member(A, Output), not_member(B, Output). mutual(Output, A, B) :- member(B, Output), not_member(A, Output).
And the query gives all the results:
?- [A,B] ins 2..5, A #< B, mutual([A,B,5],3,4), label([A,B]). A = 3, B = 5 ; A = 2, B = 3 ; A = 4, B = 5 ; A = 2, B = 4 ; false.