Prolog - Consult actually cleans current state? - prolog

I had the following code for customer creation and listing:
:-dynamic customer/2.
load:-consult('C:\\customers.txt').
save:-tell('C:\\customers.txt'), listing(customer), told.
%New customer
new_customer:-write("Name: "), read(Name),
customer_code(Code), asserta(customer(Code, Name)), save.
customer_code(Code):- customer(C, _, _, _), Code is C + 1.
customer_code(1).
So far, so good. The problem is, when trying to do more complex search, filtering and reports in general, I had to use retract to clean the current memory state of the customers.
So, before any listing, I tend to consult the file again (calling load):
list_customers:- load, listing(customer).
What goes wrong here is that more times than not, this new load will cause the listing to repeat the last customer added to the database.
Eg:
C:\customers.txt:
:-dynamic customers/2
(2, 'John')
(1, 'Alicia')
listing(customers):
(2, 'John')
(2, 'John')
(1, 'Alicia')
I've been able to avoid this by using retractall before consulting:
load:- reatractall(customer(_,_)), consult('C:\\customers.txt').
Is this a good/bad practice? I don't quite understand what's going on here or why this solves the problem.

The consult predicate, as stated in the documentation in a rather obscure place that references to a deprecated reconsult clause, states that it will reload the clauses that where loaded from the file.
What does this mean in this case?
When you first create the entries in the text file, the clauses that where loaded from the file and the clauses that you created are the same.
The problem arises when you add a new entry. Let's check this with an example to make things clear:
1) You load the file with consult:
Now your database and the file will contain the same clauses:
customers.txt:
:- dynamic customer/2.
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Your Prolog database:
:- dynamic customer/2.
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
So far, so good.
2) You add a new customer and save it to the file using tell / told:
customers.txt:
:- dynamic customer/2.
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Your Prolog database:
:- dynamic customer/2.
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Still, no issues. Here comes the real problem:
3) You reload the file:
customers.txt:
:- dynamic customer/2.
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Your Prolog database:
:- dynamic customer/2.
customer(5, 'Juan').
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
Okay, what happened here? If you remember, we previously saw that consult reload clauses that where loaded from the file.
So, the clauses we reloaded are:
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').
This leaves us with a clause, customer(5, 'Juan'), that wasn't loaded from the file the first time. So now we have to add it to our database, thus resulting in:
customer(5, 'Juan').
customer(5, 'Juan').
customer(4, 'Juan').
customer(3, 'Juan').
customer(2, 'Juan').
customer(1, 'Juan').

Related

Do not know how to say male(X) not equal to female(X)

I have the following code in prolog.
male(X).
female(X).
child(X,Y).
mother(X,Y) :- female(X), child(Y,X).
this code outputs yes even when I test it as
male(X), mother(X,Y).
I don't how should I code male(X) is not equal to female(X) in this?
I have tried mother(X,Y) :- female(X), !, +male(X), child(Y,X). But this doesn't work.

Prolog predicates involving lists

I want to write a predicate that finds a particular element in a list, by comparing the lists. For example the data I could have for instance could be like:
likes(phil, [apple, banana, orange]).
likes(hetti, [apple, cherry, grapes]).
etc.
I just want someone to explain how something like this would work, because I've been trying to use member or select; but it seems to be more difficult to find information on this. Could I use pattern matching?
It seems likely that you want to know what the common likes are between phil and hetti. If so, then this is the code:
?- bothlike(phil, hetti, Ls), write(Ls), nl.
bothlike(X, Y, Ls) :-
likes(X, Xs),
likes(Y, Ys),
intersection(Xs, Ys, Ls).
likes(phil, [apple, banana, orange]).
likes(hetti, [apple, cherry, grapes]).
intersection([], _, []).
intersection([H1|T1], L2, L3) :-
member(H1, L2),
!,
L3 = [H1|T3],
intersection(T1, L2, T3).
intersection([_|T1], L2, L3) :-
intersection(T1, L2, L3).
It gives the answer [apple].

Remove duplicate elements from list

This is my code
removevowels(L1, L2) :-
removevowels(L1, L2, []).
removevowels([], [], _).
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
not(member(X, Aux)),
removevowels(L1, L2, [X|Aux]).
removevowels([X|L1], L2, Aux) :-
not(consonant(X)),
removevowels(L1, L2, Aux).
If i run this:
?- removevowels([a,m,m,n], X).
It should print
X = [m, n]
but it's giving false and if i run this
?- removevowels([a,m,n], X).
X = [m,n]
It's alright when it doesn't have repeated elements.
Auxiliar predicates used:
member(X, [X|_]).
member(X, [_|Tail]) :-
member(X, Tail).
consonant(b)
consonant(c), etcetc ....
What's wrong in my code?
The best is to replace not/1 by the ISO (\+)/1 first.
For debugging, the first thing you would do is to minimize the problem. E.g., the query
?- removevowels([m,m],X).
is just as bad. But much smaller. So what are your rules for consonants? There is a single rule:
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
\+member(X, Aux),
removevowels(L1, L2, [X|Aux]).
So consonants have to occur only once, the next occurrence makes this fail already.
Should you still not be sure why the query fails, you might also want to generalize the query. In stead of seeing that removevowels([m,m],X) fails, you might ask
?- removevowels([m,Y],X).
which means: Is there any Y such that there is a solution. However, this method only works, if your program is "relational". In your case the last rule, however prevents this:
removevowels([X|L1], L2, Aux) :-
\+consonant(X),
removevowels(L1, L2, Aux).
It will never succeed with X being an uninstantiated variable. I'd rather use instead:
removevowels([X|L1], L2, Aux) :-
vowel(X),
removevowels(L1, L2, Aux).
Back to consonants:
What you are missing is either a separate rule for consonants that are already present, or some "defaulty" if-then-else.
Further, this extra checking might not be the most effective way to handle this. Maybe just extract the vowels first, and then sort/2 them.
in second clause, there are two 2 conditions in join, while the last clause has only one. I would commit the good case with a cut, and let the last clause only act as a trusted skip clause:
removevowels([], [], _).
removevowels([X|L1], [X|L2], Aux) :-
consonant(X),
not(member(X, Aux)),
!, removevowels(L1, L2, [X|Aux]).
removevowels([_X|L1], L2, Aux) :-
removevowels(L1, L2, Aux).
using if/then/else construct for the last 2 clauses, we avoid the problem noted by false:
removevowels([], [], _).
removevowels([X|L1], R, Aux) :-
( consonant(X),
not(member(X, Aux))
-> R=[X|L2],
removevowels(L1, L2, [X|Aux])
; removevowels(L1, R, Aux)
).

Prolog variable gets no value

I've written the following code in prolog:
contains(L1, []).
contains(L1, [X | T2]) :- member(X, L1), contains(L1, T2).
minus(L, [], L).
minus(L1, L2, L3) :- contains(L1, L3), nomembers(L3, L2).
nomembers(L1, []).
nomembers(L1, [X | T2]) :- not(member(X, L1)), nomembers(L1, T2).
contains(L1, L2) returns true if all of the members in L2 appear in L1. (contains([1,2],[1,1,1]) is true).
minus(L1, L2, L3) returns true if L3=L1\L2, meaning L3 consists of members of L1 but not of L2.
When I ask minus([1,2,3,4],[2,1],L), I get the answer that L=[], although logically it should be L=[3,4]. Does someone know why?
Above comment of mbratch is very helpful.
Notice, that your current minus(L1, L2, L3) definition is: All members of L3 are in L1 and no member from L3 is in L2.
Prolog is giving you good answer with L3 = [], it fits for definition I wrote above.
EDIT: Below code should do what you want, but currently I don't have prolog on my computer, so I can't test it.
remove(X, [X|T], T) :- !.
remove(X, [H|T], [H|T2]) :- remove(X, T, T2).
minus(L1,[],L1).
minus(L1,[H|T2],T3) :- member(H, L1), !, remove(H,L1,L4), minus(L4, T2, T3).
minus(L1,[H|T2],[H|T3]) :- minus(L1, T2, T3).
remove(X,LA,LB) which says: LB is LA without it first occurrence of X, so it's just removing element from the list.

Prolog infinite loop

This is a program that should find out who is compatible with john.
I am new to Prolog. In order to let Prolog know eg. met(X,Y) = met (Y,X)
lots of code has been written.
Now when I start the query
?- compatible(john, X)
it goes into infinite looping...
Source code:
compatible(X,Y) :- reading(X), reading(Y).
compatible(X,Y) :- football(X), football(Y).
compatible(X,Y) :- friends(X,Y).
compatible(X,Y) :- mutual(X,Y).
friends(X,Y) :- havemet(X,Y), compatible(X,Y).
havemet(X,Y) :- met(X,Y).
havemet(X,Y) :- met(Y,X).
mutual(X,Y) :- friends(X,Temp), friends(Y,Temp).
mutual(X,Y) :- friends(Temp,X), friends(Y,Temp).
mutual(X,Y) :- friends(X,Temp), friends(Temp,Y).
mutual(X,Y) :- friends(Temp,X), friends(Temp,Y).
football(john).
football(james).
friends(john, carl).
friends(carl, john).
reading(carl).
reading(fred).
reading(emily).
met(carl, emily).
met(fred, james).
met(fred, emily).
I have been researching so much but I still do not understand what is the problem and how to fix that. It would be great for me to help me.
I am not surprised you got an infinite loop. compatible depends on friends while friends depends on compatible. Are you sure this is what you want?
Please note that if you really wanted your rules to be recursive, you would need a stopping condition. But I don't see why you would need recursion for such a simple problem as affinity matching.
What Prolog system are you using? Are you required to use a particular system?
Your program as it is will not terminate in a standard Prolog, but will in a Prolog with tabling support, such as XSB-Prolog http://xsb.sourceforge.net/ or B-Prolog http://www.probp.com/ - just add :- auto_table. as a first line of your program.
| ?- compatible(john, X).
compatible(john, X).
X = john ?;
X = james ?;
X = carl ?;
X = emily ?;
no
So what is the problem with your program? Here is a way to localize the problems you have. By inserting goals false we obtain a failure slice. This is a fragment that shares still a lot of properties with the original program. In particular: if the failure-slice loops, also the original program loops. So the failure-slice shows us a part of the program that has to be modified to overcome the original problem. For your query I get the following fragment that still does not terminate:
?- compatible(john, X), false.
compatible(X,Y) :- false, reading(X), reading(Y).
compatible(X,Y) :- false, football(X), football(Y).
compatible(X,Y) :- false, friends(X,Y).
compatible(X,Y) :- mutual(X,Y), false.
friends(X,Y) :- havemet(X,Y), compatible(X,Y).
friends(john, carl) :- false.
friends(carl, john).
havemet(X,Y) :- false, met(X,Y).
havemet(X,Y) :- met(Y,X).
mutual(X,Y) :- false, friends(X,Temp), friends(Y,Temp).
mutual(X,Y) :- friends(Temp,X), friends(Y,Temp), false.
mutual(X,Y) :- friends(X,Temp), false, friends(Temp,Y).
mutual(X,Y) :- false, friends(Temp,X), friends(Temp,Y).
met(carl, emily).
met(fred, james) :- false.
met(fred, emily) :- false.
But shouldn't just any query for compatible/2 terminate? For the most general query, the failure slice can be reduced even further:
?- compatible(X, Y), false.
compatible(X,Y) :- false, reading(X), reading(Y).
compatible(X,Y) :- false, football(X), football(Y).
compatible(X,Y) :- false, friends(X,Y).
compatible(X,Y) :- mutual(X,Y), false.
friends(X,Y) :- havemet(X,Y), compatible(X,Y).
friends(john, carl) :- false.
friends(carl, john) :- false.
havemet(X,Y) :- false, met(X,Y).
havemet(X,Y) :- met(Y,X).
mutual(X,Y) :- false, friends(X,Temp), friends(Y,Temp).
mutual(X,Y) :- false, friends(Temp,X), friends(Y,Temp).
mutual(X,Y) :- friends(X,Temp), false, friends(Temp,Y).
mutual(X,Y) :- false, friends(Temp,X), friends(Temp,Y).
met(carl, emily).
met(fred, james) :- false.
met(fred, emily) :- false.
It is in the remaining part here where you have to fix the problem somehow. There might be further reasons for non-termination. But you have to fix this one in any case.
And if this is still not good enough, you might add goals V = const into the program. But I think this should suffice...

Resources