I don't understand what label does in Prolog - prolog

I went through the manual and documentation but still don't understand. I'm trying to implement a sudoku solution where after writing out all the other rules of the game, I've added label(Board) according to my teacher's instructions.
However I still don't get how it works or what it's doing. Shouldn't the other constraints(I have checks saying numbers have to be 1..9, row has to be all different,etc) give me the answer by themselves?

If you want to learn Prolog and CLP(FD) rapidly, use Prolog's top level shell to play around until you get comfortable with it. In fact, everything you need to know about CLP(FD) and Prolog can be explained there ; or almost. No need to write (what's their name?) files, everything fits in a line. Yes, I know, our parents warned us: My child, promise me, never do a one-liner. But you will learn so much faster.
So do you have the ?- waiting?
In traditional Prolog (without constraints) what you get back from a query is a so called answer substitution. In many situations, this answer substitution already describes a solution. This is the case if for each variable, a variable free term is found. Lets look at a concrete example and describe a list with 5 elements where each element is a value between 1 and 5. In this case, solutions are found for different values for L.
?- N = 5, length(L,N),maplist(between(1,N),L).
N = 5, L = [1,1,1,1,1]
; N = 5, L = [1,1,1,1,2]
; N = 5, L = [1,1,1,1,3]
; ... .
Prolog will show you only one solution (secretly hoping that you will be happy with it, it's a bit lazy, er non-strict). You get all of them typing SPACE or ;. Try it a bit just to see how many they are...
There is a total of 5^5 solutions. It's not very practical, if you just want to pick a few solutions out of that many. Large sets of solutions are represented quite ineffectively in that manner. And then, think of infinite sets! How can Prolog, or any finite being, enumerate an infinite set? We can only start to do so, finite as we are.
To overcome this, Prolog is not always forced to show concrete values, that is, solutions, but can subsume them a bit by showing answers instead:
?- N = 5, length(L,N).
N = 5, L = [_A,_B,_C,_D,_E].
This answer (-substitution) contains all 5^5 answers above, and many many more, like L = [stack,over,flow,dot,com]. In fact, it describes an infinite set of solutions! Didn't I say we finite beings can't do this? As long as we insist on concrete solutions we can't, but if we are happy with answers instead, we can do the impossible.
That idea can be extended to describe more specific sets. All with a single answer. For sets about integers, we have library(clpfd). Use it like so:
?- use_module(library(clpfd)).
?- asserta(clpfd:full_answer). % only necessary for SICStus
We can now restate our original query (in SWI, you can do Cursor up ↑ to get it):
?- N = 5, length(L,N),L ins 1..N.
N = 5, L = [_A,_B,_C,_D,_E],
_A in 1..5, _B in 1..5, _C in 1..5, _D in 1..5,_E in 1..5.
Now all 3125 solutions are compactly described with a single answer. (3125? that's 5^5). We can continue to state further requirements, like that they are all different:
?- N = 5, length(L,N),L ins 1..N, all_different(L).
N = 5, L = [_A,_B,_C,_D,_E],
_A in 1..5,_B in 1..5,_C in 1..5,_D in 1..5,_E in 1..5,
all_different([_A,_B,_C,_D,_E]).
What (practically) all constraints have in common is that they do not enumerate solutions, instead, they try to maintain consistency. Let's try this, by stating that the first element should be 1:
?- N = 5, length(L,N),L ins 1..N, all_different(L), L = [1|_].
N = 5, L = [1,_A,_B,_C,_D],
_A in 2..5,_B in 2..5,_C in 2..5,_D in 2..5,
all_different([1,_A,_B,_C,_D]).
Did you see the effect? They promptly changed their domains! Now they are all in 2..5.
And they should all be in 1..4:
?- N = 5, length(L,N),L ins 1..N, all_different(L), L = [1|_], L ins 1..4.
N = 5, L = [1,_A,_B,_C,_D],
_A in 2..4,_B in 2..4,_C in 2..4,_D in 2..4,
all_different([1,_A,_B,_C,_D]).
Again, they are updated. But ... think of it: There are 4 variables left, they should all be different but there are only 3 different values for them.
So we have caught Prolog being a bit too lazy. There actually is a better constraint called all_distinct/1 that would fail now, but no matter how many clever constraints a system has, there will be always such inconsistencies. Ask Professor Gödel. The only ways to bail out would be errors or infinite loops.
So we need another method to be sure that an answer does describe real solutions. Enter labeling! With label/1 or labeling/2 we can eliminate all those strange constraints and bust inconsistencies:
?- N = 5, length(L,N),L ins 1..N, all_different(L), L = [1|_], L ins 1..4, labeling([], L).
false.
?- N = 5, length(L,N),L ins 1..N, all_different(L), L = [1|_], labeling([], L).
N = 5, L = [1,2,3,4,5]
; N = 5, L = [1,2,3,5,4]
; N = 5, L = [1,2,4,3,5]
; ... .
How can we be sure that these are real solutions? Easy: They do not contain any extra goals besides answer substitutions1. For if we forgot some:
?- N = 5, length(L,N),L ins 1..N, all_different(L), L = [1,B,C|_], labeling([],[B,C]).
N = 5, L = [1,2,3,_A,_B], B = 2, C = 3,
_A in 4..5, _B in 4..5,
all_different([1,2,3,_A,_B]),
They would show.
SWI's labeling/2 has a very useful guarantee:
Labeling is always complete, always terminates, and yields no redundant solutions.
1 Since the SWI toplevel does not show all constraints, you would need to wrap call_residue_vars(Goal, Vs) around it. But for simple top level queries, above is good enough.

Roughly, there are 2 phases in constraint programming: constraint propagation and search.
Constraint propagation alone can give concrete values, and it often does. But in general, it only reduces domain (set of the possible values for a variable) to a smaller subset, and then you need search (label values from a subset, obtained with constraint propagation).
Very simple example (pseudocode):
A #:: 0..1,
B #:: 0..1,
A #\= B
Constraint propagation cannot solve this by itself, it cannot even reduce domain of A or B - it can only create a delayed constraint. After that a search (label) tries a value 0 for A, the delayed constraint fires up, and domain of B reduced to {1}.
In contrast, this can be solved with constraint propagation alone:
A #:: 1,
B #:: 0..1,
A #\= B

Related

Function to find a list in prolog

I am new to Prolog and I am trying to write a function that finds a list that follows some rules.
More specifically, given two numbers, N and K, I want my function to find a list with K powers of two that their sum is N. The list must not contain each power but the total sum of each power. For example if N=13 and K=5, I want my list to be [2,2,1] where the first 2 means two 4, the second 2 means two 2, and the third 1 means one 1 (4+4+2+2+1=13). Consider that beginning from the end of the list each position i represents the 2^i power of 2. So I wrote this code:
sum2(List, SUM, N) :-
List = [] -> N=SUM;
List = [H|T],
length(T, L),
NewSUM is SUM + (H * 2**L),
sum2(T, NewSUM, N).
powers2(N,K,X):-
sum2(X,0,N),
sum_list(X, L),
K = L.
The problem is:
?- sum2([2,2,1],0,13).
true.
?- sum2([2,2,1],0,X).
X = 13.
?- sum2(X,0,13).
false.
?- powers2(X,5,[2,2,1]).
X = 13.
?- powers2(13,5,[2,2,1]).
true.
?- powers2(13,X,[2,2,1]).
X = 5.
?- powers2(13,5,X).
false.
In the cases, X represents the list I expected the output to be a list that follows the rules and not false. Could you help me to find how can I solve this and have a list for output in these cases?
The immediate reason for the failure of your predicate with an unbound list is due to your use of the -> construct for control flow.
Here is a simplified version of what you are trying to do, a small predicate for checking whether a list is empty or not:
empty_or_not(List, Answer) :-
( List = []
-> Answer = empty
; List = [H|T],
Answer = head_tail(H, T) ).
(Side note: The exact layout is a matter of taste, but you should always use parentheses to enclose code if you use the ; operator. I also urge you to never put ; at the end of a line but rather in a position where it really sticks out. Using ; is really an exceptional case in Prolog, and if it's formatted too similarly to ,, it can be hard to see that it's even there, and what parts of the clause it applies to.)
And this seems to work, right?
?- empty_or_not([], Answer).
Answer = empty.
?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).
OK so far, but what if we call this with an unbound list?
?- empty_or_not(List, Answer).
List = [],
Answer = empty.
Suddenly only the empty list is accepted, although we know from above that non-empty lists are fine as well.
This is because -> cuts away any alternatives once it has found that its condition is satisfied. In the last example, List is a variable, so it is unifiable with []. The condition List = [] will succeed (binding List to []), and the alternative List = [H|T] will not be tried. It seems simple, but -> is really an advanced feature of Prolog. It should only be used by more experienced users who know that they really really will not need to explore alternatives.
The usual, and usually correct, way of implementing a disjunction in Prolog is to use separate clauses for the separate cases:
empty_or_not([], empty).
empty_or_not([H|T], head_tail(H, T)).
This now behaves logically:
?- empty_or_not([], Answer).
Answer = empty.
?- empty_or_not([1, 2, 3], Answer).
Answer = head_tail(1, [2, 3]).
?- empty_or_not(List, Answer).
List = [],
Answer = empty ;
List = [_2040|_2042],
Answer = head_tail(_2040, _2042).
And accordingly, your definition of sum2 should look more like this:
sum2([], SUM, N) :-
N = SUM.
sum2([H|T], SUM, N) :-
length(T, L),
NewSUM is SUM + (H * 2**L),
sum2(T, NewSUM, N).
This is just a small step, however:
?- sum2(X, 0, 13).
ERROR: Arguments are not sufficiently instantiated
ERROR: In:
ERROR: [9] _2416 is 0+_2428* ...
ERROR: [8] sum2([_2462],0,13) at /home/gergo/sum.pl:5
ERROR: [7] <user>
You are trying to do arithmetic on H, which has no value. If you want to use "plain" Prolog arithmetic, you will need to enumerate appropriate values that H might have before you try to do arithmetic on it. Alternatively, you could use arithmetic constraints. See possible implementations of both at Arithmetics in Prolog, represent a number using powers of 2.

How to generate a list with some numbers?

I want to generate a list with all the numbers abc, where a = c and b >= a + c.
I know how to generate the numbers, but I do not know how to add them to the list because I can not do something like L = [Number|L].
I don't know how to define the add predicate... or should I do it in another way?
I have tried defining it as add(Nr, L, [Nr|L])., but I have no idea of what to do after that.
c(0). c(1). c(2). c(3). c(4). c(5). c(6). c(7). c(8). c(9).
bts(L, Lr) :- c(A), A =\= 0, c(C), A =:= C, c(B), C =\=9, B >= A + C,
Nr is A * 100 + B * 10 + C,
add(......).
solve(L) :- bts([], L).
The output should be:
L=[121,131,141,151,161,171,181,191,242,252,262,272,282,292,363,373,383,393,484,494]
You are on the right track. Here are two small tips:
First and most importantly, focus on what a single solution looks like. You can always use meta-predicates like findall/3 and setof/3 to collect all solutions into a list of solutions.
Second, there are more intelligent ways to describe solutions in your case. Currently, you are using generate and test, which is an infeasible strategy for larger problems. Instead, use your Prolog system's constraint solvers to declaratively describe all requirements. This lets the engine apply pruning to avoid generating all combinations.
In total, my recommendation is to do it similar to the following:
abc(Ls) :-
Ls = [A,B,C],
A #= C,
A #\= 0,
C #\= 9,
B #>= A + C,
Ls ins 0..9.
We can now try the most general query to see what solutions look like in general:
?- abc(Ls).
Ls = [_940, _946, _940],
_940 in 1..4,
2*_940#=<_946,
_946 in 2..9.
This is of course not very useful, but it at least tells us that our relation terminates and is deterministic.
This means that so-called labeling, which is the search for concrete solutions will also terminate. That is a very nice property, because it means that the search will always terminate, even if it may take a long time.
In this case, the search is of course trivial, and we can use for example label/1 to enumerate solutions:
?- abc(Ls), label(Ls).
Ls = [1, 2, 1] ;
Ls = [1, 3, 1] ;
Ls = [1, 4, 1] ;
Ls = [1, 5, 1] ;
etc.
Now, to obtain the results you want, we will use findall/3 to collect all solutions into a list:
?- abc(Ls),
findall(N, (label(Ls),
atomic_list_concat(Ls,A),atom_number(A,N)), Ns).
Ls = [_774, _780, _774],
Ns = [121, 131, 141, 151, 161, 171, 181, 191, 242|...],
_774 in 1..4,
2*_774#=<_780,
_780 in 2..9.
I have also taken the liberty to apply a small transformation to each solution, so that you get the desired result immediately.
The formalism I am applying here is called CLP(FD), and the exact details for invoking this mechanism differ slightly between available Prolog systems. Check your system's manual for more information, and see also clpfd.
a simple application of findall/3 and between/3
abc(Ns) :- findall(N, (between(1,9,A),between(1,9,B),C=A,B>=A+C,N is A * 100 + B * 10 + C), Ns).
This is the solution I found:
bts(1000, []) :- !.
bts(Nr, L) :-
N is Nr + 1,
bts(N, X),
once(((number_chars(Nr, [H1, H2, H3]), number_chars(A, [H1]), number_chars(C, [H3]),
A =:= C, number_chars(B, [H2]), B >= A + C,
L = [Nr|X]);
L = X)).
solve(L) :- bts(100, L).

How can I replace a list in Prolog?

I think it's very easy but I have no idea how to do that.
I tried by attribuition, doing a list receive another list but don't work.
% H is the head of a coordenate and T the tail
% E is the element that will be placed in the position T
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],H,T,E,NewTray) :-
H is 1,replace(L1,T,E,N),L1 = N;
H is 2,replace(L2,T,E,N),L2 = N;
...
H is 10,replace(L10,T,E,N),L10 = N;
NewTray = [L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10].
I need that L1 be the N in this clause, I don't know how I can create a clause to modify the L1 inside the clause findLine. I thought in create clause to remove all elements and add the new ones one by one and call this at the attribuition place:
%L is the list, C a counter and N the new list
rewrite(L,C,N) :-
Q is C,
removeByIndex(Q,L,R),
(Q \== 0 -> rewrite(R,Q-1,N), !.
removeByIndex(0,[_|T],T):- !.
removeByIndex(I,[H|T],R):- X is I - 1, removeByIndex(X, T, Y), insert(H, Y, R).
But I continous with the same problem: the L1 are not modified :(
The idea is modify a line and replace on the tray.
PS: I'm sorry for my english, but the prolog topics are almost inative in the portuguese forum
I'm really unsure what you're trying to accomplish here, but I can point to a few things that strike me as symptoms of a misunderstanding.
First of all, you bind all the variables at the top and then you have essentially a bottom-out else case that looks like this:
NewTray = [L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10].
Well, you never assign to NewTray in any of your other cases, so NewTray is going to be uninstantiated most of the time. That does not seem likely to be what you intend to me.
Second, your cases have this structure:
H is 1,replace(L1,T,E,N),L1 = N;
First mistake here is that H is 1; is/2 is for evaluating arithmetic expressions; there's no difference between this and H = 1, and the equivalence of L1 and N means that this whole predicate could probably be written as:
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],1,T,E,_) :-
replace(L1,T,E,L1).
findLine([L0,L1,L2,L3,L4,L5,L6,L7,L8,L9,L10],2,T,E,_) :-
replace(L2,T,E,L2).
findLine(Line, _, _, Line).
I'm still confused by what you're trying to do, looking at that.
I suspect that you think L1 will have some value on the way into the relation and suddenly have a new, different value after the relation is used. That is emphatically not the case: variables in Prolog are bound exactly once; your assignment L1 = N or whatever is not going to cause L1 to "receive a new value" (because such a thing cannot happen in Prolog); instead it informs Prolog that L1 and N should be bound to the same value. What this means depends on circumstances; if they are both ground and not equal it will cause your predicate to fail, for instance, but if either of them is non-ground they will accept the value of the other.
I'm looking at what you're doing here and I can't help but think that you're essentially trying to do this:
replace([], _, _, []).
replace([H|T], 1, X, [X|T]).
replace([H|T], N, X, [H|Replaced]) :-
N > 1, succ(N0, N), replace(T, N0, X, Replaced).
Use it like this:
?- replace([1,2,3,4,5], 3, foo, Result).
Result = [1, 2, foo, 4, 5]
I just can't for the life of me figure out what you're trying to do, and I don't know why you're bothering to bind all the variables in your list at once if you don't need them all at once.
Anyway, I hope this helps! Maybe if you show us more of what you're trying to do it will be more clear how we can help.
Edit: Elaboration on = and unification
Let's mess around with = and see what happens:
?- X = 3.
X = 3.
Probably nothing surprising about this.
?- 3 = X.
X = 3.
Unification is different from assignment. As you can see, it is not directional. This line would not have worked in any other language.
?- X = [1,Y,3].
X = [1, Y, 3].
Notice that Prolog has no issues with having variables remain free.
?- X = [1,Y,3], Y = 2.
X = [1, 2, 3],
Y = 2.
Now, because Y is the same in both positions, when you bound Y to 2, the middle value in X became 2 as well. There are data structures unique to Prolog that make use of this feature (difference lists).
?- X = [1,Y,3], Q = X, Q = [1,2,3].
X = Q, Q = [1, 2, 3],
Y = 2.
Now what makes this interesting is that we did not explicitly tell Prolog that Y is 2. Prolog inferred this by unification. You can see some more examples of that here:
?- X = [H|T], H = 3, T = [4,5].
X = [3, 4, 5],
H = 3,
T = [4, 5].
So here we said, X is composed of H and T and then told it what H and T are. But Prolog's unification doesn't care much about the order you do things:
?- X = [H|T], X = [1,2,3].
X = [1, 2, 3],
H = 1,
T = [2, 3].
Unification is transitive.
So what happens when Prolog cannot unify?
?- X = [1,Y,3], Q = X, Q = [1,2,3], Y = 4.
false.
Y has to be 2 for the first step, but it has to be 4 for the last step. Once a variable is bound, there's no changing it. This is just a more complex way of saying:
?- X = 2, X = 4.
false.
Prolog does not have "assignables", just variables.

Define the predicate Prolog

I'm reviewing some exercise for the coming test and having difficulty at this.
Given a list of integers L, define the predicate: add(L,S) which returns a list of integers S in which each element is the sum of all the elements in L up to the same position.
Example:
?- add([1,2,3,4,5],S).
S = [1,3,6,10,15].
So my question is what define the predicate means? It looks pretty general. I've read some threads but they did not provide much. Thanks!
This is a good exercise to familiarize yourself with two important Prolog concepts:
declarative integer arithmetic to reason about integers in all directions
meta-predicates to shorten your code.
We start with a very simple relation, relating an integer I and a sum of integers S0 to a new sum S:
sum_(I, S0, S) :- S #= S0 + I.
Depending on your Prolog system, you may need a directive like:
:- use_module(library(clpfd)).
to use declarative integer arithmetic.
Second, there is a powerful family of meta-predicates (see meta-predicate) called scanl/N, which are described in Richard O'Keefe's Prolog library proposal, and already implemented in some systems. In our case, we only need scanl/4.
Example query:
?- scanl(sum_, [1,2,3,4,5], 0, Sums).
Sums = [0, 1, 3, 6, 10, 15].
Done!
In fact, more than done, because we can use this in all directions, for example:
?- scanl(sum_, Is, 0, Sums).
Is = [],
Sums = [0] ;
Is = [_2540],
Sums = [0, _2540],
_2540 in inf..sup ;
Is = [_3008, _3014],
Sums = [0, _3008, _3044],
_3008+_3014#=_3044 ;
etc.
This is what we expect from a truly relational solution!
Note also the occurrence of 0 as the first element in the list of partial sums. It satisfies your textual description of the task, but not the example you posted. I leave aligning these as an exercise.
Define the predicate simply means write a predicate that does what the question requires.
In your question you have to write the definition of add/2 predicate( "/2" means that it has two arguments). You could write the definition below:
add(L,S):- add1(L,0,S).
add1([],_,[]).
add1([H|T],Sum,[H1|T1]):- H1 is Sum+H,NSum is Sum+H,add1(T,NSum,T1).
The above predicate gives you the desired output. A simple example:
?- add([1,2,3,4,5],S).
S = [1, 3, 6, 10, 15].
I think the above or something similar predicate is what someone would wait to see in a test.
Some additional information-issues
The problem with the predicate above is that if you query for example:
?- add(S,L).
S = L, L = [] ;
ERROR: is/2: Arguments are not sufficiently instantiated
As you see when you try to ask when your predicate succeeds it gives an obvious solutions and for further solutions it throws an error. This is not a very good-desired property. You could improve that by using module CLPFD:
:- use_module(library(clpfd)).
add(L,S):- add1(L,0,S).
add1([],_,[]).
add1([H|T],Sum,[H1|T1]):- H1 #= Sum+H,NSum #= Sum+H,add1(T,NSum,T1).
Now some querying:
?- add([1,2,3,4,5],S).
S = [1, 3, 6, 10, 15].
?- add(S,[1,3,6]).
S = [1, 2, 3].
?- add(S,L).
S = L, L = [] ;
S = L, L = [_G1007],
_G1007 in inf..sup ;
S = [_G1282, _G1285],
L = [_G1282, _G1297],
_G1282+_G1285#=_G1307,
_G1282+_G1285#=_G1297 ;
...and goes on..
As you can see now the predicate is in the position to give any information you ask! That's because now it has a more relational behavior instead of the functional behavior that it had before due to is/2 predicate. (These are some more information to improve the predicate's behavior. For the test you might not be allowed to use libraries etc... so you may write just a simple solution that at least answers the question).

SWI Prolog Clpfd Library - Reification

I have an upcoming Logic exam and have been studying some past papers from my course. I've come across a question regarding reification and have posted it below;
Illustrate reification by using it to express the property that a variable B can
either take the value of 1 or 8.
After reading some resources and looking at the SWI Prolog manual, I still find the concept of reification quite confusing (primarily studying Java so the switch to learning Prolog has been difficult). It's quite confusing having to use boolean logic within the prolog query.
Without reification, I would have to write the following code (which I know is far too long to be the correct answer);
B in 1..8, B #\= 2,B #\= 3,B #\= 4,B #\= 5,B #\= 6,B #\= 7.
Would really appreciate if someone could show me the above query, but using reification.
From the documentation:
The constraints in/2, #=/2, #\=/2, #/2, #==/2 can be reified, which means reflecting their truth values into Boolean values represented by the integers 0 and 1. Let P and Q denote reifiable constraints or Boolean variables, then:
...
P #\/ Q True iff either P or Q
...
For you, it seems P is B #= 1 and Q is B #= 8, so you end up with:
?- B #= 1 #\/ B #= 8.
B in 1\/8.
As you see, you are not really using the reified values. You are just using reification as a round-about way of declaring the domain of your variable. The answer to your query, B in 1 \/ 8, is what you would probably use directly if you wanted to say that "B is either 1 or 8". If you look carefully at the documentation of in/2, you should see that the domain can be either an integer, a range Lower .. Upper, or the union of Domain1 \/ Domain2. In your case both domains are a single integer, 1 and 8.
PS: Once you go down that road, why not:
?- B in 1..8 #/\ #\ B in 2..7.
B in 1\/8.
B is in [1,8] AND B is not in [2,7].
The possibilities are endless :)
First, try out your query:
?- B in 1..8, B #\= 2,B #\= 3,B #\= 4,B #\= 5,B #\= 6,B #\= 7.
B in 1\/8.
This tells you that your query is equivalent to the single goal B in 1\/8.
From this, you see that you don't need reification to express that a finite domain variable is either equal to 1 or 8.
Reification allows you to reify the truth value of the constraint. For example, you can say:
?- T #<==> B in 1\/8.
T in 0..1,
B in 1\/8#<==>T.
?- T #<==> B in 1\/8, B = 3.
T = 0,
B = 3.
From the second query, you see that if B = 3, then T = 0, because the constraint B in 1\/8 doesn't hold in that case.
Reifying a constraint can be useful if you want to reason about constraints themselves. For example, this allows you to express that a certain number of list elements must be equal to a given integer. I leave solving this as a more meaningful exercise to understand reification.
Initially I was thinking along the same lines as #Boris and #mat. But after pondering the question for a while, another possible interpretation of the task occured to me. However, keep in mind that I am not familiar with your course material, so this is highly speculative. That being said, maybe the task description is asking to write a predicate that evaluates to true if the above property holds or to false otherwise. A predicate like that could be defined as:
val_either_or_t(X,Y,Z,true) :-
( X#=Y ; X#=Z).
val_either_or_t(X,Y,Z,false) :-
X #\= Y,
X #\= Z.
I admit the name is a little clumsy but I couldn't really come up with a better one. Anyway, it does the job according to the task interpretation I described above:
?- val_either_or_t(X,1,8,T).
T = true,
X = 1 ? ;
T = true,
X = 8 ? ;
T = false,
X in inf..0\/2..7\/9..sup
?- val_either_or_t(X,Y,Z,T).
T = true,
X = Y,
X in inf..sup ? ;
T = true,
X = Z,
X in inf..sup ? ;
T = false,
X#\=Z,
X#\=Y
I came up with this idea because lately I was playing around with some reifying predicates that I found on Stackoverflow, and it popped into my mind that the task might be aimed in a direction where the described property could be used as a condition with such predicates. For example with if_/3 that I used a lot with (=)/3 in the condition, but why not use it with something like val_either_or_t/4. Consider the following minimal example:
a(condition_was_true).
b(condition_was_false).
somepredicate(X,Y) :-
if_(val_either_or_t(X,1,8),a(Y),b(Y)).
With the respective query:
?- somepredicate(X,Y).
X = 1,
Y = condition_was_true ? ;
X = 8,
Y = condition_was_true ? ;
Y = condition_was_false,
X in inf..0\/2..7\/9..sup
This example is of course not very meaningful and only intended to illustrate how reification of the given property might be used. Also, I am using the atoms true and false to reify the thruth values with regard to using them with if_/3. However, you can also use 1 and 0 to reify truth values like in #mat's example. Just replace the 4th argument in the definition of val_either_or_t/4 by 1 and 0 respectively. Furthermore you might find the refinement of this idea that was suggested by #repeat in the comments interesting as well.

Resources