Prolog: simulate disjunctive facts - prolog

I've got a logic problem that I'd like to solve, so I thought, "I know, I'll try Prolog!"
Unfortunately, I'm running into a brick wall almost immediately. One of the assumptions involved is a disjunctive fact; either A, B or C is true (or more than one), but I do not know which. I've since learned that this is something Prolog does not support.
There's a lot of documentation out there that seems to address the subject, but most of it seems to immediately involve more intricate concepts and solves more advanced problems. What I'm looking for is an isolated way to simulate defining the above fact (as defining it straight away is, by limitations of Prolog, not possible).
How could I address this? Can I wrap it in a rule somehow?
EDIT: I realise I have not been very clear. Given my lack of familiarity with Prolog, I did not want to get caught up in a syntax error when trying to convey the problem, and instead went with natural language. I guess that did not work out, so I'll give it a shot in pseudo-Prolog anyway.
Intuitively, what I would want to do would be something like this, to declare that either foo(a), foo(b) or foo(c) holds, but I do not know which:
foo(a); foo(b); foo(c).
Then I would expect the following result:
?- foo(a); foo(b); foo(c).
true
Unfortunately, the fact I'm trying to declare (namely foo(x) holds for at least one x \in {a, b, c}) cannot be defined as such. Specifically, it results in No permission to modify static procedure '(;)/2'.
Side-note: after declaring the disjunctive fact, the result of ?- foo(a). would be a bit unclear to me from a logical perspective; it is clearly not true, but false does not cover it either -- Prolog simply does not have sufficient information to answer that query in this case.
EDIT 2: Here's more context to make it more of a real-world scenario, as I might have over-simplified and lost details in translation.
Say there are three people involved. Alice, Bob and Charlie. Bob holds two cards out of the set {1, 2, 3, 4}. Alice asks him questions, in response to which he shows her one card that Charlie does not see, or shows no cards. In case more cards are applicable, Bob shows just one of them. Charlie's task is to learn what cards Bob is holding. As one might expect, Charlie is an automated system.
Alice asks Bob "Do you have a 1 or a 2?", in response to which Bob shows Alice a card. Charlie now learns that Bob owns a 1 or a 2.
Alice then asks "Do you have a 2 or a 3", to which Bob has no cards to show. Clearly, Bob had a 1, which he showed Alice previously. Charlie should now be able to derive this, based on these two facts.
What I'm trying to model is the knowledge that Bob owns a 1 or a 2 (own(Bob, 1) \/ own(Bob, 2)), and that Bob does not own a 2 or a 3 (not (own(Bob, 2) \/ own(Bob, 3))). Querying if Bob owns a 1 should now be true; Charlie can derive this.

The straight-forward answer to your question:
if you can model your problem with constraint logic programming over finite domains, then, an "exclusive or" can be implemented using #\ as follows:
Of the three variables X, Y, Z, exactly one can be in the domain 1..3.
D = 1..3, X in D #\ Y in D #\ Z in D
To generalize this, you can write:
disj(D, V, V in D #\ Rest, Rest).
vars_domain_disj([V|Vs], D, Disj) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
and use it as:
?- vars_domain_disj([X,Y,Z], 2 \/ 4 \/ 42, D).
D = (Y in 2\/4\/42#\ (Z in 2\/4\/42#\ (X in 2\/4\/42#\D))).
If you don't use CLP(FD), for example you can't find a nice mapping between your problem and integers, you can do something else. Say your variables are in a list List, and any of them, but exactly one, can be foo, and the rest cannot be foo, you can say:
?- select(foo, [A,B,C], Rest), maplist(dif(foo), Rest).
A = foo,
Rest = [B, C],
dif(B, foo),
dif(C, foo) ;
B = foo,
Rest = [A, C],
dif(A, foo),
dif(C, foo) ;
C = foo,
Rest = [A, B],
dif(A, foo),
dif(B, foo) ;
false.
The query reads: in the list [A,B,C], one of the variables can be foo, then the rest must be different from foo. You can see the three possible solutions to that query.
Original answer
It is, sadly, often claimed that Prolog does not support one thing or another; usually, this is not true.
Your question is not exactly clear at the moment, but say you mean that, with this program:
foo(a).
foo(b).
foo(c).
You get the following answer to the query:
?- foo(X).
X = a ;
X = b ;
X = c.
Which you probably interpreted as:
foo(a) is true, and foo(b) is true, and foo(c) is true.
But, if I understand your question, you want a rule which says, for example:
exactly one of foo(a), foo(b), and foo(c) can be true.
However, depending on the context, that it, the rest of your program and your query, the original solution can mean exactly that!
But you really need to be more specific in your question, because the solution will depend on it.
Edit after edited question
Here is a solution to that particular problem using constraint programming over finite domains with the great library(clpfd) by Markus Triska, available in SWI-Prolog.
Here is the full code:
:- use_module(library(clpfd)).
cards(Domain, Holds, QAs) :-
all_distinct(Holds),
Holds ins Domain,
maplist(qa_constraint(Holds), QAs).
qa_constraint(Vs, D-no) :-
maplist(not_in(D), Vs).
qa_constraint([V|Vs], D-yes) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
not_in(D, V) :- #\ V in D.
disj(D, V, V in D #\ Rest, Rest).
And two example queries:
?- cards(1..4, [X,Y], [1 \/ 2 - yes, 2 \/ 3 - no]), X #= 1.
X = 1,
Y = 4 ;
false.
If the set of cards is {1,2,3,4}, and Bob is holding two cards, and when Alice asked "do you have 1 or 2" he said "yes", and when she asked "do you have 2 or 3" he said no, then: can Charlie know if Bob is holding a 1?
To which the answer is:
Yes, and if Bob is holding a 1, the other card is 4; there are no further possible solutions.
Or:
?- cards(1..4, [X,Y], [1 \/ 2 - yes, 2 \/ 3 - no]), X #= 3.
false.
Same as above, can Charlie know if Bob is holding a 3?
Charlie knows for sure that Bob is not holding a three!
What does it all mean?
:- use_module(library(clpfd)).
Makes the library available.
cards(Domain, Holds, QAs) :-
all_distinct(Holds),
Holds ins Domain,
maplist(qa_constraint(Holds), QAs).
This defines the rule we can query from the top level. The first argument must be a valid domain: in your case, it will be 1..4 that states that cards are in the set {1,2,3,4}. The second argument is a list of variables, each representing one of the cards that Bob is holding. The last is a list of "questions" and "answers", each in the format Domain-Answer, so that 1\/2-yes means "To the question, do you hold 1 or 2, the answer is 'yes'".
Then, we say that all cards that Bob holds are distinct, and each of them is one of the set, and then we map each of the question-answer pairs to the cards.
qa_constraint(Vs, D-no) :-
maplist(not_in(D), Vs).
qa_constraint([V|Vs], D-yes) :-
foldl(disj(D), Vs, Disj, V in D #\ Disj).
The "no" answer is easy: just say that for each of the cards Bob is holding, it is not in the provided domain: #\ V in D.
not_in(D, V) :- #\ V in D.
The "yes" answer means that we need an exclusive or for all cards Bob is holding; 2\/3-yes should result in "Either the first card is 2 or 3, or the second card is 2 or 3, but not both!"
disj(D, V, V in D #\ Rest, Rest).
To understand the last one, try:
?- foldl(disj(2\/3), [A,B], Rest, C in 2\/3 #\ Rest).
Rest = (A in 2\/3#\ (B in 2\/3#\ (C in 2\/3#\Rest))).

A generate-and-test solution in vanilla Prolog:
card(1). card(2). card(3). card(4).
owns(bob, oneof, [1,2]). % i.e., at least one of
owns(bob, not, 2).
owns(bob, not, 3).
hand(bob, Hand) :-
% bob has two distinct cards:
card(X), card(Y), X < Y, Hand = [X, Y],
% if there is a "oneof" constraint, check it:
(owns(bob, oneof, S) -> (member(A,S), member(A, Hand)) ; true),
% check all the "not" constraints:
((owns(bob, not, Card), member(Card,Hand)) -> false; true).
Transcript using the above:
$ swipl
['disjunctions.pl'].
% disjunctions.pl compiled 0.00 sec, 9 clauses
true.
?- hand(bob,Hand).
Hand = [1, 4] ;
;
false.
Note that Prolog is Turing complete, so generally speaking, when someone says "it can't be done in Prolog" they usually mean something like "it involves some extra work".

Just for the sake of it, here is a small program:
card(1). card(2). card(3). card(4). % and so on
holds_some_of([1,2]). % and so on
holds_none_of([2,3]). % and so on
holds_card(C) :-
card(C),
holds_none_of(Ns),
\+ member(C, Ns).
I have omitted who owns what and such. I have not normalized holds_some_of/1 and holds_none_of/1 on purpose.
This is actually enough for the following queries:
?- holds_card(X).
X = 1 ;
X = 4.
?- holds_card(1).
true.
?- holds_card(2).
false.
?- holds_card(3).
false.
?- holds_card(4).
true.
which comes to show that you don't even need the knowledge that Bob is holding 1 or 2. By the way, while trying to code this, I noticed the following ambiguity, from the original problem statement:
Alice asks Bob "Do you have a 1 or a 2?", in response to which Bob shows Alice a card. Charlie now learns that Bob owns a 1 or a 2.
Does that now mean that Bob has exactly one of 1 and 2, or that he could be holding either one or both of the cards?
PS
The small program above can actually be reduced to the following query:
?- member(C, [1,2,3,4]), \+ member(C, [2,3]).
C = 1 ;
C = 4.

(Eep, I just realized this is 6 years old, but maybe it's interesting to introduce logic-programming languages with probabilistic choices for the next stumbler )
I would say the accepted answer is the most correct, but if one is interested in probabilities, a PLP language such as problog might be interesting:
This example assumes we don't know how many cards bob holds. It can be modified for a fixed number of cards without much difficulty.
card(C):- between(1,5,C). % wlog: A world with 5 cards
% Assumption: We don't know how many cards bob owns. Adapting to a fixed number of cards isn't hard either
0.5::own(bob, C):-
card(C).
pos :- (own(bob,1); own(bob,2)).
neg :- (own(bob,2); own(bob,3)).
evidence(pos). % tells problog pos is true.
evidence(\+neg). % tells problog neg is not true.
query(own(bob,Z)).
Try it online: https://dtai.cs.kuleuven.be/problog/editor.html#task=prob&hash=5f28ffe6d59cae0421bb58bc892a5eb1
Although the semantics of problog are a bit harder to pick-up than prolog, I find this approach an interesting way of expressing the problem. The computation is also harder, but that's not necessarily something the user has to worry about.

Related

How can Prolog derive nonsense results such as 3 < 2?

A paper I'm reading says the following:
Plaisted [3] showed that it is possible to write formally correct
PROLOG programs using first-order predicate-calculus semantics and yet
derive nonsense results such as 3 < 2.
It is referring to the fact that Prologs didn't use the occurs check back then (the 1980s).
Unfortunately, the paper it cites is behind a paywall. I'd still like to see an example such as this. Intuitively, it feels like the omission of the occurs check just expands the universe of structures to include circular ones (but this intuition must be wrong, according to the author).
I hope this example isn't
smaller(3, 2) :- X = f(X).
That would be disappointing.
Here is the example from the paper in modern syntax:
three_less_than_two :-
less_than(s(X), X).
less_than(X, s(X)).
Indeed we get:
?- three_less_than_two.
true.
Because:
?- less_than(s(X), X).
X = s(s(X)).
Specifically, this explains the choice of 3 and 2 in the query: Given X = s(s(X)) the value of s(X) is "three-ish" (it contains three occurrences of s if you don't unfold the inner X), while X itself is "two-ish".
Enabling the occurs check gets us back to logical behavior:
?- set_prolog_flag(occurs_check, true).
true.
?- three_less_than_two.
false.
?- less_than(s(X), X).
false.
So this is indeed along the lines of
arbitrary_statement :-
arbitrary_unification_without_occurs_check.
I believe this is the relevant part of the paper you can't see for yourself (no paywall restricted me from viewing it when using Google Scholar, you should try accessing this that way):
Ok, how does the given example work?
If I write it down:
sm(s(s(s(z))),s(s(z))) :- sm(s(X),X). % 3 < 2 :- s(X) < X
sm(X,s(X)). % forall X: X < s(X)
Query:
?- sm(s(s(s(z))),s(s(z)))
That's an infinite loop!
Turn it around
sm(X,s(X)). % forall X: X < s(X)
sm(s(s(s(z))),s(s(z))) :- sm(s(X),X). % 3 < 2 :- s(X) < X
?- sm(s(s(s(z))),s(s(z))).
true ;
true ;
true ;
true ;
true ;
true
The deep problem is that X should be Peano number. Once it's cyclic, one is no longer in Peano arithmetic. One has to add some \+cyclic_term(X) term in there. (maybe later, my mind is full now)

How to write a Prolog program

I don't know how to write a Prolog program for the following scenario.
1. If any two person having same hobby then they like each other.
2. Every gardener likes the Sun.
I did this but I don't know whether it is correct or not.
like(gardener,sun).
Please help me to solve it.
Prolog rules follow the "reversed-IF" template:
Head :- Goal1, ..., GoalN.
means (roughly), "Head holds if Goal1, ..., GoalN all hold".
Put the other way around it means, "if Goal1, ..., GoalN all hold, then Head also holds".
This fits exactly your first sentence, thus it can be encoded as a rule:
likes(A, B) :- % Head :-
hobby( A, HobbyA), % Goal1,
hobby( B, HobbyB), % Goal2,
same( HobbyA, HobbyB), % Goal3,
dif( A, B). % Goal4.
% different persons, not the same one
The second sentence too fits the same template:
likes(A, sun) :-
isA(A, gardner).
With the most natural encoding of isA( X, Y) as simply a unification X = Y, this becomes equivalent to the fact that you wrote. Facts are rules with no body.

Counter-intuitive behavior of min_member/2

min_member(-Min, +List)
True when Min is the smallest member in the standard order of terms. Fails if List is empty.
?- min_member(3, [1,2,X]).
X = 3.
The explanation is of course that variables come before all other terms in the standard order of terms, and unification is used. However, the reported solution feels somehow wrong.
How can it be justified? How should I interpret this solution?
EDIT:
One way to prevent min_member/2 from succeeding with this solution is to change the standard library (SWI-Prolog) implementation as follows:
xmin_member(Min, [H|T]) :-
xmin_member_(T, H, Min).
xmin_member_([], Min0, Min) :-
( var(Min0), nonvar(Min)
-> fail
; Min = Min0
).
xmin_member_([H|T], Min0, Min) :-
( H #>= Min0
-> xmin_member_(T, Min0, Min)
; xmin_member_(T, H, Min)
).
The rationale behind failing instead of throwing an instantiation error (what #mat suggests in his answer, if I understood correctly) is that this is a clear question:
"Is 3 the minimum member of [1,2,X], when X is a free variable?"
and the answer to this is (to me at least) a clear "No", rather than "I can't really tell."
This is the same class of behavior as sort/2:
?- sort([A,B,C], [3,1,2]).
A = 3,
B = 1,
C = 2.
And the same tricks apply:
?- min_member(3, [1,2,A,B]).
A = 3.
?- var(B), min_member(3, [1,2,A,B]).
B = 3.
The actual source of confusion is a common problem with general Prolog code. There is no clean, generally accepted classification of the kind of purity or impurity of a Prolog predicate. In a manual, and similarly in the standard, pure and impure built-ins are happily mixed together. For this reason, things are often confused, and talking about what should be the case and what not, often leads to unfruitful discussions.
How can it be justified? How should I interpret this solution?
First, look at the "mode declaration" or "mode indicator":
min_member(-Min, +List)
In the SWI documentation, this describes the way how a programmer shall use this predicate. Thus, the first argument should be uninstantiated (and probably also unaliased within the goal), the second argument should be instantiated to a list of some sort. For all other uses you are on your own. The system assumes that you are able to check that for yourself. Are you really able to do so? I, for my part, have quite some difficulties with this. ISO has a different system which also originates in DEC10.
Further, the implementation tries to be "reasonable" for unspecified cases. In particular, it tries to be steadfast in the first argument. So the minimum is first computed independently of the value of Min. Then, the resulting value is unified with Min. This robustness against misuses comes often at a price. In this case, min_member/2 always has to visit the entire list. No matter if this is useful or not. Consider
?- length(L, 1000000), maplist(=(1),L), min_member(2, L).
Clearly, 2 is not the minimum of L. This could be detected by considering the first element of the list only. Due to the generality of the definition, the entire list has to be visited.
This way of handling output unification is similarly handled in the standard. You can spot those cases when the (otherwise) declarative description (which is the first of a built-in) explicitly refers to unification, like
8.5.4 copy_term/2
8.5.4.1 Description
copy_term(Term_1, Term_2) is true iff Term_2 unifies
with a term T which is a renamed copy (7.1.6.2) of
Term_1.
or
8.4.3 sort/2
8.4.3.1 Description
sort(List, Sorted) is true iff Sorted unifies with
the sorted list of List (7.1.6.5).
Here are those arguments (in brackets) of built-ins that can only be understood as being output arguments. Note that there are many more which effectively are output arguments, but that do not need the process of unification after some operation. Think of 8.5.2 arg/3 (3) or 8.2.1 (=)/2 (2) or (1).
8.5.4 1 copy_term/2 (2),
8.4.2 compare/3 (1),
8.4.3 sort/2 (2),
8.4.4 keysort/2 (2),
8.10.1 findall/3 (3),
8.10.2 bagof/3 (3),
8.10.3 setof/3 (3).
So much for your direct questions, there are some more fundamental problems behind:
Term order
Historically, "standard" term order1 has been defined to permit the definition of setof/3 and sort/2 about 1982. (Prior to it, as in 1978, it was not mentioned in the DEC10 manual user's guide.)
From 1982 on, term order was frequently (erm, ab-) used to implement other orders, particularly, because DEC10 did not offer higher-order predicates directly. call/N was to be invented two years later (1984) ; but needed some more decades to be generally accepted. It is for this reason that Prolog programmers have a somewhat nonchalant attitude towards sorting. Often they intend to sort terms of a certain kind, but prefer to use sort/2 for this purpose — without any additional error checking. A further reason for this was the excellent performance of sort/2 beating various "efficient" libraries in other programming languages decades later (I believe STL had a bug to this end, too). Also the complete magic in the code - I remember one variable was named Omniumgatherum - did not invite copying and modifying the code.
Term order has two problems: variables (which can be further instantiated to invalidate the current ordering) and infinite terms. Both are handled in current implementations without producing an error, but with still undefined results. Yet, programmers assume that everything will work out. Ideally, there would be comparison predicates that produce
instantiation errors for unclear cases like this suggestion. And another error for incomparable infinite terms.
Both SICStus and SWI have min_member/2, but only SICStus has min_member/3 with an additional argument to specify the order employed. So the goal
?- min_member(=<, M, Ms).
behaves more to your expectations, but only for numbers (plus arithmetic expressions).
Footnotes:
1 I quote standard, in standard term order, for this notion existed since about 1982 whereas the standard was published 1995.
Clearly min_member/2 is not a true relation:
?- min_member(X, [X,0]), X = 1.
X = 1.
yet, after simply exchanging the two goals by (highly desirable) commutativity of conjunction, we get:
?- X = 1, min_member(X, [X,0]).
false.
This is clearly quite bad, as you correctly observe.
Constraints are a declarative solution for such problems. In the case of integers, finite domain constraints are a completely declarative solution for such problems.
Without constraints, it is best to throw an instantiation error when we know too little to give a sound answer.
This is a common property of many (all?) predicates that depend on the standard order of terms, while the order between two terms can change after unification. Baseline is the conjunction below, which cannot be reverted either:
?- X #< 2, X = 3.
X = 3.
Most predicates using a -Value annotation for an argument say that pred(Value) is the same
as pred(Var), Value = Var. Here is another example:
?- sort([2,X], [3,2]).
X = 3.
These predicates only represent clean relations if the input is ground. It is too much to demand the input to be ground though because they can be meaningfully used with variables, as long as the user is aware that s/he should not further instantiate any of the ordered terms. In that sense, I disagree with #mat. I do agree that constraints can surely make some of these relations sound.
This is how min_member/2 is implemented:
min_member(Min, [H|T]) :-
min_member_(T, H, Min).
min_member_([], Min, Min).
min_member_([H|T], Min0, Min) :-
( H #>= Min0
-> min_member_(T, Min0, Min)
; min_member_(T, H, Min)
).
So it seems that min_member/2 actually tries to unify Min (the first argument) with the smallest element in List in the standard order of terms.
I hope I am not off-topic with this third answer. I did not edit one of the previous two as I think it's a totally different idea. I was wondering if this undesired behaviour:
?- min_member(X, [A, B]), A = 3, B = 2.
X = A, A = 3,
B = 2.
can be avoided if some conditions can be postponed for the moment when A and B get instantiated.
promise_relation(Rel_2, X, Y):-
call(Rel_2, X, Y),
when(ground(X), call(Rel_2, X, Y)),
when(ground(Y), call(Rel_2, X, Y)).
min_member_1(Min, Lst):-
member(Min, Lst),
maplist(promise_relation(#=<, Min), Lst).
What I want from min_member_1(?Min, ?Lst) is to expresses a relation that says Min will always be lower (in the standard order of terms) than any of the elements in Lst.
?- min_member_1(X, L), L = [_,2,3,4], X = 1.
X = 1,
L = [1, 2, 3, 4] .
If variables get instantiated at a later time, the order in which they get bound becomes important as a comparison between a free variable and an instantiated one might be made.
?- min_member_1(X, [A,B,C]), B is 3, C is 4, A is 1.
X = A, A = 1,
B = 3,
C = 4 ;
false.
?- min_member_1(X, [A,B,C]), A is 1, B is 3, C is 4.
false.
But this can be avoided by unifying all of them in the same goal:
?- min_member_1(X, [A,B,C]), [A, B, C] = [1, 3, 4].
X = A, A = 1,
B = 3,
C = 4 ;
false.
Versions
If the comparisons are intended only for instantiated variables, promise_relation/3 can be changed to check the relation only when both variables get instantiated:
promise_relation(Rel_2, X, Y):-
when((ground(X), ground(Y)), call(Rel_2, X, Y)).
A simple test:
?- L = [_, _, _, _], min_member_1(X, L), L = [3,4,1,2].
L = [3, 4, 1, 2],
X = 1 ;
false.
! Edits were made to improve the initial post thanks to false's comments and suggestions.
I have an observation regarding your xmin_member implementation. It fails on this query:
?- xmin_member(1, [X, 2, 3]).
false.
I tried to include the case when the list might include free variables. So, I came up with this:
ymin_member(Min, Lst):-
member(Min, Lst),
maplist(#=<(Min), Lst).
Of course it's worse in terms of efficiency, but it works on that case:
?- ymin_member(1, [X, 2, 3]).
X = 1 ;
false.
?- ymin_member(X, [X, 2, 3]).
true ;
X = 2 ;
false.

Prolog Loops until True

I'm pretty new to Prolog but I'm trying to get this program to give me the first set of twin primes that appears either at or above N.
twins(M) :-
M2 is M + 2,
twin_prime(M, M2),
write(M),
write(' '),
write(M2).
M3 is M + 1,
twins(M3).
However, I'm not completely sure how to go about getting it to loop and repeat until it's true. I've tried using the repeat/0 predicate but I just get stuck in an infinite loop. Does anyone have any tips I could try? I'm pretty new to Prolog.
You're on the right track using tail recursion and #Jake Mitchell's solution works swell. But here are some tips that might help clarify a few basic concepts in Prolog:
First, it seems like your predicate twins/1 is actually defining a relationship between 2 numbers, namely, the two twin primes. Since Prolog is great for writing very clear, declarative, relational programs, you might make the predicate more precise and explicit by making it twin_primes/2. (That this should be a binary predicate is also pretty clear from your name for the predicate, since one thing cannot be twins...)
One nice bonus of explicitly working with a binary predicate when describing binary relations is that we no longer have to fuss with IO operations to display our results. We'll simply be able to query twin_primes(X,Y) and have the results returned as Prolog reports back on viable values of X and Y.
Second, and more importantly, your current definition of twins/1 wants to describe a disjunction: "twins(M) is true if M and M + 2 are both prime or if M3 is M + 3 and twins(M3) is true". The basic way of expressing disjunctions like this is by writing multiple clauses. A single clause of the form <Head> :- <Body> declares that the Head is true if all the statements composing the Body are true. Several clauses with the same head, like <Head> :- <Body1>. <Head> :- <Body2>. ..., declare that Head is true if Body1 is true or if Body2 is true. (Note that a series of clauses defining rules for a predicate are evaluated sequentially, from top to bottom. This is pretty important, since it introduces non-declarative elements into the foundations of our programs, and it can be exploited to achieve certain results.)
In fact, you are only a small step from declaring a second rule for twins/1. You just tried putting both clause-bodies under the same head instance. Prolog requires the redundant measure of declaring two different rules in cases like this. Your code should be fine (assuming your definition of twin_prime/2 works), if you just change it like so:
twins(M) :-
M2 is M + 2,
twin_prime(M, M2),
write(M),
write(' '),
write(M2).
twins(M) :-
\+twin_prime(M, M2), %% `\+` means "not"
M3 is M + 1,
twins(M3).
Note that if you take advantage of Prolog's back-tracking, you often don't actually need to effect loops through tail recursion. For example, here's an alternative approach, taking into account some of what I advised previously and using a quick (but not as in "efficient" or "fast") and dirty predicate for generating primes:
prime(2).
prime(P) :-
between(2,inf,P),
N is (P // 2 + 1),
forall(between(2,N,Divisor), \+(0 is P mod Divisor)).
twin_primes(P1, P2) :-
prime(P1),
P2 is P1 + 2,
prime(P2).
twin_primes/2 gets a prime number from prime/1, then calculates P2 and checks if it is prime. Since prime/1 will generate an infinite number of primes on backtracking, twin_primes/2 will just keep asking it for numbers until it finds a satisfactory solution. Note that, if called with two free variables, this twin_primes/2 will generate twin primes:
?- twin_primes(P1, P2).
P1 = 3,
P2 = 5 ;
P1 = 5,
P2 = 7 ;
P1 = 11,
P2 = 13 ;
P1 = 17,
P2 = 19 ;
P1 = 29,
P2 = 31 ;
But it will also verify if two numbers are twin primes if queried with specific values, or give you the twin of a prime, if it exists, if you give a value for P1 but leave P2 free:
?- twin_primes(3,Y). Y = 5.
There's a handy if-then-else operator that works well for this.
twin_prime(3,5).
twin_prime(5,7).
twin_prime(11,13).
next_twin(N) :-
A is N+1,
B is N+2,
(twin_prime(N,B) ->
write(N),
write(' '),
write(B)
;
next_twin(A)).
And a quick test:
?- next_twin(5).
5 7
true.
?- next_twin(6).
11 13
true.

Use cut in Prolog to define a once_member/2 function

Disclaimer: This is informal and non-assessed coursework to do in my own time. I have tried it myself, failed and am now looking for some guidance.
I am trying to implement a version of the member/2 function which will only return members for a list once.
For example:
| ?- member(X, [1,2,3,1]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
X = 1 ? ;
I would like it to only print out each number a maximum of once.
| ?- once_member(X, [1,2,3,1]).
X = 1 ? ;
X = 2 ? ;
X = 3 ? ;
no
We have been told to do this with the cut '!' operator but I have looked over the notes for my course for cut and more online and yet still can't make it click in my head!
So far I have managed to get:
once_member(E, [E | L]) :- !.
once_member(E, [_, L]) :-
once_member(E, L).
Which returns 1 and then nothing else, I feel like my cut is in the wrong place and preventing a backtrack for each possible match but I'm really not sure where to go with it next.
I have looked in my course notes and also at: http://www.cs.ubbcluj.ro/~csatol/log_funk/prolog/slides/5-cuts.pdf and Programming in Prolog (Google Books)
Guidance on how to logically apply the cut would be most useful, but the answer might help me figure that out myself.
We have also been told to do another method which uses '\+' negation by failure but hopefully this may be simpler once cut has twigged for me?
Remove redundant answers and stay pure!
We define memberd/2 based on if_/3 and (=)/3:
memberd(X, [E|Es]) :-
if_(X = E, true, memberd(X, Es)).
Particularly with meta-predicates, a different argument order may come in handy sometimes:
list_memberd(Es, X) :-
memberd(X, Es).
Sample query:
?- memberd(X, [1,2,3,1]).
X = 1 ;
X = 2 ;
X = 3 ;
false.
The solution with cut... at first it sounds quite troublesome.
Assuming that the first argument will be instantiated, a solution is trivial:
once_member(X,L):-
member(X,L),!.
but this will not have the behavior you want if the first arg is not instantiated.
If we know the domain of the lists elements (for example numbers between 1 and 42) we could instantiate the first argument:
once_member(X,L):-
between(1,42,X),
member_(X,L).
member_(X,L):-
member(X,L),!.
but this is veeery inefficient
at this point, I started to believe that it's not possible to do with just a cut (assuming that we dont use + or list_to_set/2
oh wait! < insert idea emoticon here >
If we could implement a predicate (like list_to_set/2 of swi-prolog) that would take a list and produce a list in which all the duplicate elements are removed we could simply use the normal member/2 and don't get duplicate results. Give it a try, I think that you will be able to write it yourself.
--------Spoilers------------
one_member(X,L):-
list_to_set(L,S),
member(X,S).
list_to_set([],[]).
list_to_set([H|T],[H|S]):-
remove_all(H,T,TT),
list_to_set(TT,S).
%remove_all(X,L,S): S is L if we remove all instances of X
remove_all(_,[],[]).
remove_all(X,[X|T],TT):-
remove_all(X,T,TT),!.
remove_all(X,[H|T],[H|TT]):-
remove_all(X,T,TT).
As you see we have to use a cut in remove_all/3 because otherwise the third clause can be matched by remove_all(X,[X|_],_) since we do not specify that H is different from X. I believe that the solution with not is trivial.
Btw, the solution with not could be characterized as more declarative than the solution with cut; the cut we used is typically called a red cut since it alters the behavior of the program. And there are other problems; note that, even with the cut, remove_all(1,[1,2],[1,2]) would succeed.
On the other hand it's not efficient to check twice for a condition. Therefore, the optimal would be to use the if-then-else structure (but I assume that you are not allowed to use it either; its implementation can be done with a cut).
On the other hand, there is another, easier implementation with not: you should not only check if X is member of the list but also if you have encountered it previously; so you will need an accumulator:
-------------Spoilers--------------------
once_member(X,L):-
once_member(X,L,[]).
once_member(X,[X|_T],A):-
\+once_member(X,A).
once_member(X,[H|T],A):-
once_member(X,T,[H|A]).
once_member(X, Xs) :-
sort(Xs, Ys),
member(X, Ys).
Like almost all other solutions posted, this has some anomalies.
?- X = 1, once_member(X, [A,B]).
X = A, A = 1
; X = B, B = 1.
?- X = 1, once_member(X, [A,A]).
X = A, A = 1.
Here's an approach that uses a cut in the definition of once_member/2 together with the classic member/2 predicate:
once_member(X,[H|T]) :-
member(H,T),
!,
once_member(X,T).
once_member(H,[H|_]).
once_member(X,[_|T]) :-
once_member(X,T).
Applied to the example above:
?- once_member(X,[1,2,3,1]).
X = 2 ;
X = 3 ;
X = 1 ;
no
Note: Despite the odd-appearing three clause definition, once_member/2 is last-call/tail-recursive optimization eligible due to the placement of the cut ahead of its first self-invocation.

Resources