How to find someone who only published one book? - prolog

Hello I am using ECliPSe Prolog to do some homework and was have a problem with one of my questions. I want to find people that have only published one book using the below Prolog program that I have created.
hasBook(markham_library,dave,"Artifical Intelligence: A Modern Approach",1).
hasBook(indigo,levesque,"the two",2).
hasBook(union_library,dave,"the three",3).
hasBook(somewhere_library,bob,"Thinking as Computation",4).
hasBook(amazon,robert,"the five",5).
hasBook(ajax_library,daniel ,"the six",6).
hasBook(markham_library,evan,"Computational Intelligence",7).
hasBook(stouffvile_library,john ,"the eight",8).
hasBook(ajax_library,sam,"the nine",9).
hasBook(kitchner_library,david,"the ten",10).
hasBook(amazon,chad,"the eleven",105).
hasBook(amazon,chad, "the twelve", 107).
hasBook(amazon,chad, "the thirteen",10).
hasBook(amazon,chad, "the fourteen", 20).
hasBook(amazon,jkrowling,"harrypotter",10).
hasBook(markham_library,jkrowling,"harrypotter",5).
lives(brad,markham).
lives(joyce,stouffville).
lives(opal,union).
lives(delia,ajax).
lives(verna,ville).
lives(sean,ajax).
lives(william,kitchner).
lives(casey,ajax).
lives(courtney,markham).
lives(garrett,stouffville).
lives(chad,newyork).
shipping(markham_library, union, 1).
shipping(stouffville_library, toronto, 2).
shipping(markham_library, stouffville, 3).
shipping(stouffville_library, stouffville, 4).
shipping(markham_library, markham, 5).
shipping(stouffville_library, ajax, 6).
shipping(markham_library, kitchner, 7).
shipping(stouffville_library, kitchner, 11).
shipping(union_library, markham, 9).
shipping(union_library, stouffville, 2).
shipping(amazon, stouffville, 5).
shipping(amazon, markham, 17).
shipping(amazon, toronto, 20).
shipping(markham_library, toronto, 5).
I do not understand why the query hasBook(V,W,X,Y), not hasBook(L,W,N,M). does not return a result. Instead it returns false. Can someone please explain.

Not sure if this is the solution you are supposed to come up with but you can use the setof/3 predicate to group all solutions by author and pick only those where the result list has one element:
?- Xs = [_], setof(Book, Lib^N^hasBook(Lib,Name,Book,N), Xs).
Xs = ["Thinking as Computation"],
Name = bob ;
Xs = ["the six"],
Name = daniel ;
Xs = ["the ten"],
Name = david ;
Xs = ["Computational Intelligence"],
Name = evan ;
Xs = ["the eight"],
Name = john ;
Xs = ["the two"],
Name = levesque ;
Xs = ["the five"],
Name = robert ;
Xs = ["the nine"],
Name = sam.
The pattern Lib^N^ binds the two variables in hasBook(Lib,Name,Book,N) such that if the same book appears in different libraries, it will not give a separate result. Using setof/3 instead of bagof/3 makes sure that only one result per Name/Book pair is returned.
Edit: sorry, I forgot to explain why your solution does not work. Let me rewrite the old style not to \+ and hide all the singleton variables in your query:
?- hasBook(_,W,B1,_), \+ hasBook(_,W,B2,_).
false.
You're looking for an assignment that finds a book B1 by W but then you assert that W has not written any books which can not be true because we have already found B1. As #Ruzihm pointed out, you are missing the information that the second query is not about B1. Their solution uses \= but this only works after the second query has sufficiently instantiated B2 to compare it to B1. An alternative is to use dif/2:
?- dif(B1,B2), hasBook(_,W,B1,_), \+ hasBook(_,W,B2,_).
The difference is that dif/2 introduces a constraint that B1 and B2 are different. As long as one of them is still a variable, this can not be decided yet. Your database has only ground facts where the problem does not arise. In general, using dif/2 is less problematic though.

You need to indicate that the books, N and X need to be different in order to be thrown out.
hasBook(_,X,A,_), not(( hasBook(_,X,B,_), B\=A) ) will throw away any results with the same author and a different book, and not care about the 1st or the 4th arguments.
Confirm at https://swish.swi-prolog.org/p/fkukVFSw.swinb

Related

How to attach properties to terms?

I want to attach properties to my terms, from a set of about 50 different properties. Usually only a small subset of them are used for a given term. There are many ways to represent these properties, but I am not satisfied with any of them.
For the sake of discussion, here is a set of properties and their possible values:
hair: bald, blonde, brune, red
eyes: blue, green, brown
first_name: John, Dick, Harry
There are many ways to represent these properties, for example with a list of pairs:
[eyes-blue, hair-blonde]
The only representation that seems to work is to use a very long list, where each index is used for a specific property:
?- T1=[blonde,_,_], T2=[_,blue,_], T1=T2.
T1 = T2, T2 = [blonde, blue, _1266]
?- T1=[X,_,_], X=blue.
T1 = [blue, _1230, _1236],
X = blue
But it's unreadable with 50 properties, and very bugprone (in my case, a whole set of predicates is dedicated to each property, and sometimes to each value of a property).
The way I would use such a feature would be by having conditions like "Terms T1 and T2 have the same value for property X", or "Terms T1 and T2 are the same", where T1 and T2 have attributes which can be set elsewhere, or can be left unset.
Using dicts desn't work, because unset keys are considered non-existent:
?- T1 = _{eyes:blue, hair:blonde}, T2 = _{eyes:blue}, T1 = T2.
false.
For this to work, I would need to initialize each term with the 50 (mostly irrelevant) properties with free variables, on the off-chance that some of them will be used.
What other options do I have? I am open to using a different logic programming language if there is something closer to my needs than prolog.
With the "very long list", you have indeed found one possible representation that lets you directly use Prolog's built-in unification to perform the task for you.
As you note, this comes at a price though: It's unreadable, error-prone, wasteful etc.
There are many possible ways to solve the task, and I would like to give you two pointers that I hope you find relevant for your task.
Option 1: Use lists of pairs
This is in fact already mentioned in your post. Pairs of the form hair-blonde etc. are a natural way to represent the available data. By convention, (-)/2 is frequently used to denote pairs in Prolog.
All that is missing is precisely describing what "merging" such pairs means. You call it "unification", so let us use this terminology although it is of course different from syntactic unification that is available with (=)/2. One way to define the relation we want is:
unify_pairs([], APs, APs).
unify_pairs([A1-P1|APs1], APs2, APs) :-
if_(selectd_t(A1-P1, APs2, APs2Rest),
APs=[A1-P1|Rest],
if_(attr_exists_t(A1, APs2),
false,
APs = [A1-P1|Rest])),
unify_pairs(APs1, APs2Rest, Rest).
attr_exists_t(A, APs, T) :-
pairs_keys(APs, As),
memberd_t(A, As, T).
selectd_t(E, Xs0, Xs, T) :-
i_selectd_t(Xs0, Xs, E, T).
i_selectd_t([], [], _, false).
i_selectd_t([X|Xs], Rest, E, T) :-
if_(X=E, (T=true,Rest=Xs), (Rest = [X|Rs],i_selectd_t(Xs, Rs, E, T))).
This uses library(reif) and two auxiliary predicates to distinguish the different cases.
Your test cases work as required. For example:
?- unify_pairs([hair-blonde], [eyes-blue], Ps).
Ps = [hair-blonde, eyes-blue].
?- unify_pairs([eyes-blue], [eyes-brown], Ps).
false.
Importantly, we can use it in all directions, and so we can also post significantly more general queries. For example:
?- unify_pairs([T1-P1], [T2-P2], TPs).
T1 = T2,
P1 = P2,
TPs = [T2-P2] ;
TPs = [T1-P1, T2-P2],
dif(T2, T1),
dif(f(T2, P2), f(T1, P1)).
Such answers help us to obtain a better understanding of the relation, and to test it more exhaustively.
Option 2: Use lists of pairs again
The second pointer I would like to include is found in library(ordsets) and similar libraries that ship with several Prolog systems.
This again lets you use lists, even lists of pairs. Importantly, lists are available in all Prolog systems. Various operations are quite efficient due to the way these libraries represent sets as ordered lists.
However, the price you may pay in such cases is the generality explained in the first approach. I suggest you first try the more general approach (i.e., Option 1), and then, only if necessary, resort to lower-level approaches that are more error-prone and less general.
You maybe say "unification" but you mean something different from what unification normally means in Prolog which is why your question might be mistaken for a different question. You could do some things with SWI-Prolog dicts:
?- _{hair:blonde, eyes:blue} >:< _{eyes:blue}.
true.
?- _{hair:blonde, eyes:blue} >:< _{eyes:blue, hair:Color}.
Color = blonde.
?- _{hair:blonde, eyes:blue} >:< _{eyes:blue, hair:bald}.
false.
but you cannot directly do what you need, because if you "put" into a dict you add or replace which is not what you want.
?- R =_{eyes:blue}.put(_{hair:blonde}).
R = _7436{eyes:blue, hair:blonde}.
(this one was OK)
?- R =_{eyes:blue}.put(_{eyes:brown}).
R = _7436{eyes:brown}.
(this is not what you want, is it?)
what you want I don't know what to call in words but it is some form of finding union on keys in key-value pairs. But you can just do it with dicts I think if you first do P1 >:< P2 and then put_dict(P1, P2, Result)?
?- P1 = _{eyes:blue},
P2 = _{hair:blonde,eyes:brown},
P1 >:< P2, put_dict(P1, P2, Result).
false.
?- P1 = _{eyes:blue},
P2 = _{hair:blonde},
P1 >:< P2, put_dict(P1, P2, Result).
Result = _10044{eyes:blue, hair:blonde}.
?- P1 = _{eyes:blue},
P2 = _{hair:blonde,eyes:blue},
P1 >:< P2, put_dict(P1, P2, Result).
Result = _10046{eyes:blue, hair:blonde}.
Please respond if this is what you were asking because I am really not sure? But what is even more important actually is that you think a bit more carefully about the real problem you are trying to model because maybe? (just maybe?) you are thinking of it in terms of solution that is not as good as another solution that will make the problem be a lesser problem or a problem with already existing better solutions. Maybe it will help if you provide even more context about your problem in your question, because now there is enough context about how you tried to solve it but I don't know what you are really solving.
You could make the attributes one-arity terms, like this:
hair(bald)
hair(blonde)
eyes(blue)
eyes(green)
...
That would rule out unifications like
hair(blonde) = hair(red)
and you could quite easily write your own predicate for combining two lists, which could also block/filter out multiple instances of the same attribute.
In languages with strong typing this is a nice representation, but I'm not sure it's so useful in Prolog. Anyway it is a possibility.
I think I understand your question but I don't think I understand your difficulty. You could achieve what you want with dicts, with assocs, with lists of pairs.... You say:
Terms T1 and T2 have the same value for property X
Here it is with dicts, like the answer by #User9213:
?- _{a:1, foo:2, bar:3}.a = _{a:2, foo:22, baz:33}.a.
false.
?- _{a:1, foo:2, bar:3}.a = _{a:1, foo:22, baz:33}.a.
true.
In other words, to compare a "property" of two dicts, you just say Dict1.X = Dict2.X. Note that this also works with X a variable:
?- X = a, _{a:1, b:2}.X = _{a:1, b:432432}.X.
X = a.
The same would work with any other option already mentioned: with library(assoc) (just get the values for that key and compare), or even for lists of pairs (just do member(Key-Value, List) and compare values).
Then, you also say,
Terms T1 and T2 are the same
Now you really can just compare dicts. For assocs, I am not certain if two assocs are always the same if they have the same contents, but you can make lists and compare those. And if you keep your lists of pairs sorted on keys, you can just compare, as with dicts.
Finally, you say:
where T1 and T2 have attributes which can be set elsewhere, or can be left unset.
This is ambiguous. If an attribute is unset, just leave it out of the dict/assoc/list. "Set elsewhere" I really don't get.
You need to write some code down and get a feel for how things could be done. Showing your difficulties with a code example will help you get specific and useful answers.

Querying a Prolog knowledge base

% A quiz team structure takes the form:
% team(Captain, Vice_captain, Regular_team_members).
% Captain and Vice_captain are player structures;
% Regular_team_members is a list of player structures.
% player structures take the form:
% player(First_name, Surname, details(Speciality,Recent_score)).
I've been given the following Prolog database:
team(player(niall,elliott,details(history,11)),
player(michelle,cartwright,details(fashion,19)),
[player(peter,lawlor,details(science,12)),
player(louise,boyle,details(current_affairs,17))
]
).
What would be the code needed to get the firstname and the recent score of all players whose recent score is above 15?
I've tried using exists but it keeps giving me errors.
Second question:
I need to get the surname of any vice-captain whose team includes a captain or a regular team member whose speciality is science.
I can get the surname of the vice-captains by using the first line below, but the second part is more tricky.
part_two(Surname):-
team(_,player(_,Surname,_),_),
Regular_player = team(_,_,player(_,_,details(science,_))),
Captain = team(player(_,_,details(science,_),_,_)).
A more detailed description of what you tried and how it didn't work would be better because (a) some people are reluctant to do your homework for you, and (b) we can better clear up your misunderstandings if we know what those misunderstandings are.
Anyway, Prolog programming is all about decomposing problems.
The first problem is to find out which players exist at all. A player is a team captain or a team vice captain or a regular team member. This definition has three parts separated by "or", which suggests that we need a predicate composed of three clauses:
player(Captain) :-
team(Captain, _, _).
player(Vice_captain) :-
team(_, Vice_captain, _).
player(Regular_player) :-
team(_, _, Regular_members),
member(Regular_player, Regular_members).
We can test this:
?- player(P).
P = player(niall, elliott, details(history, 11)) ;
P = player(michelle, cartwright, details(fashion, 19)) ;
P = player(peter, lawlor, details(science, 12)) ;
P = player(louise, boyle, details(current_affairs, 17)).
Now we want to identify "good players". You wrote that you have "tried using exists". There is no exists in Prolog, and it isn't needed. In order to express something like "there exists a player P such that ...", we just define a predicate containing the goal player(P) and some other goals expressing the property we are interested in. This leads to a definition like this:
good_player(First_name, Recent_score) :-
player(P),
P = player(First_name, _, details(_, Recent_score)),
Recent_score > 15.
You can read this as "there is a player P with first name First_name and recent score Recent_score such that the recent score is greater than 15".
?- good_player(F, S).
F = michelle,
S = 19 ;
F = louise,
S = 17.

Prolog: simulate disjunctive facts

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.

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.

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