Unfortunately, I cannot give the full text of the problem for some reason. Therefore, I will try to describe the main point.
There was a murder at the hotel in room 4. 6 visitors are suspected who came to visit someone in one of the 6 hotel rooms at different intervals (These are all facts).
Then all the suspects were interviewed, some evidence was considered and information was received from the receptionist (These are the rules).
You need to find out who was where at what time. Well, and therefore who is the killer.
my problem
I am not getting the correct result.
When calling
guest(brown, R, T).
i get false (brawn must be a killer)
and basically when i call the function
solution(Guests).
then I get a very large number of lists. And the rules are not followed in them. Why is that?
result lists screenshoot
In short, I have a suspicion that these rules work somehow separately. But I could be wrong, because in the prologue I am a complete zero. What's my mistake?
P.S. If necessary, I can try to write the full text of the assignment. The only problem is that the text is in a different language from an old book that was scanned..
The reason why your query fails is the following program fragment. I obtained it by systematically generalizing away goal after goal by adding a * in front. Because this fragment fails, also your original program will fail. I am sure it will be evident to you how to interpret this:
:- op(950, fy, *). % auxiliary definition
*_.
:- initialization(guest(brown, _R, _T)). % your failing query
evidence(taylor,R,_):- *not(R=5).
evidence(white,R,_):- *not(R=5).
evidence(smith,R,_):- *not(R=1), *not(R=3), *not(R=6), *not(R=5).
evidence(green,R,_):- *not(R=3), *not(R=6).
guest(N,R,T):-
*interrogation(N,R,T),
evidence(N,R,T),
*receptionist(N,R,T).
Just a remark, instead of not(A=B) rather use dif(A,B). It's the 21st century...
I am very new to Prolog and trying to learn.
For my program, I would like to have the user provide pairs of strings which are "types of".
For example, user provides at command line the strings "john" and "man". These atoms would be made to be equal, i.e. john(man).
At next prompt, then user provides "man" and "tall", again program asserts these are valid, man(tall).
Then the user could query the program and ask "Is john tall?". Or in Prolog: john(tall) becomes true by transitive property.
I have been able to parse the strings from the user's input and assign them to variables Subject and Object.
I tried a clause (where Subject and Object are different strings):
attribute(Subject, Object) :-
assert(term_to_atom(_ , Subject),
term_to_atom(_ , Object)).
I want to assert the facts that Subject and Object are valid pair. If the user asserts it, then they belong to together. How do I force this equality of the pairs?
What's the best way to go about this?
Questions of this sort have been asked a lot recently (I guess your professors all share notes or something) so a browse through recent history might have been productive for you. This one comes to mind, for instance.
Your code is pretty wide of the mark. This is what you're trying to do:
attribute(Subject, Object) :-
Fact =.. [Object, Subject],
assertz(Fact).
Using it works like this:
?- attribute(man, tall).
true.
?- tall(X).
X = man.
So, here's what you should notice about this code:
We're using =../2, the "univ" operator, to build structures from lists. This is the only way to create a fact from some atoms.
I've swapped subject and object, because doing it the other way is almost certainly not what you want.
The predicate you want is assertz/1 or asserta/1, not assert/2. The a and z on the end just tells Prolog whether you want the fact at the beginning or end of the database.
Based on looking at your code, I think you have a lot of baggage you need to shed to become productive with Prolog.
Prolog predicates do not return values. So assert(term_to_atom(... wasn't even on the right track, because you seemed to think that term_to_atom would "return" a value and it would get substituted into the assert call like in a functional or imperative language. Prolog just plain works completely differently from that.
I'm not sure why you have an empty variable in your term_to_atom predicates. I think you did that to satisfy the predicate's arity, but this predicate is pretty useless unless you have one ground term and one variable.
There is an assert/2, but it doesn't do what you want. It should be clear why assert normally only takes one argument.
Prolog facts should look like property(subject...). It is not easy to construct facts and then query them, which is what you'd have to do using man(tall). What you want to say is that there is a property, being tall, and man satisfies it.
I would strongly recommend you back up and go through some basic Prolog tutorials at this point. If you try to press forward you're only going to get more lost.
Edit: In response to your comment, I'm not sure how general you want to go. In the basic case where you're dealing with a 4-item list with [is,a] in the middle, this is sufficient:
build_fact([Subject,is,a,Object], is_a(Subject, Object)).
If you want to isolate the first and last and create the fact, you have to use univ again:
build_fact([Subject|Rest], Fact) :-
append(PredicateAtoms, [Object], Rest),
atomic_list_concat(PredicateAtoms, '_', Predicate),
Fact =.. [Predicate, Subject, Object].
Not sure if you want to live with the articles ("a", "the") that will wind up on the end though:
?- build_fact([john,could,be,a,man], Fact).
Fact = could_be_a(john, man)
Don't do variable fact heads. Prolog works best when the set of term names is fixed. Instead, make a generic place for storing properties using predefined, static term name, e.g.:
is_a(john, man).
property(man, tall).
property(john, thin).
(think SQL tables in a normal form). Then you can use simple assertz/1 to update the database:
add_property(X, Y) :- assertz(property(X, Y)).
ok, so there's basically 3 tasks this program must carry out:
Parse a sentence given in the form of a list, in this case (and throughout the example) the sentence will be [the,traitorous,tostig_godwinson,was,slain]. (its history, don't ask!) so this would look like:
sentence(noun_phrase(det(the),np2(adj(traitorous),np2(noun(tostig_godwinson)))),verb_phrase(verb(slain),np(noun(slain)))).
use the parsed sentence to extract the subject, verb and object, and output as a list, e.g. [tostig_godwinson,was,slain] using the current example. I had this working too until I attempted number 3.
use the target list and compare it against a knowledge base to basically answer the question you asked in the 1st place (see code below) so using this question and the knowledge base the program would print out 'the_battle_of_stamford_bridge' as this is the sentence in the knowledge base with the most matches to the list in question
so here's where i am so far:
history('battle_of_Winwaed',[penda, king_of_mercia,was,slain,killed,oswui,king_of_bernicians, took_place, '15_November_1655']).
history('battle_of_Stamford_Bridge',[tostig_godwinson,herald_hardrada,was,slain, took_place, '25_September_1066']).
history('battle_of_Boroughbridge',[edwardII,defeated,earl_of_lancaster,execution, took_place, '16_march_1322']).
history('battle_of_Towton',[edwardIV,defeated,henryVI,palm_Sunday]).
history('battle_of_Wakefield',[richard_of_york, took_place,
'30_December_1490',was,slain,war_of_the_roses]).
history('battle_of_Adwalton_Moor',[earl_of_newcastle,defeats,fairfax, took_place, '30_June_1643',battle,bradford,bloody]).
history('battle_of_Marston_Moor',[prince_rupert,marquis_of_newcastle,defeats,fairfax,oliver_cromwell,ironsides, took_place,
'2_June_1644', bloody]).
noun(penda).
noun(king_of_mercia).
noun(oswui).
noun(king_of_bernicians).
noun('15_November_1655').
noun(tostig_godwinson).
noun(herald_hardrada).
noun('25_September_1066').
noun(edwardII).
noun(earl_of_lancaster).
noun('16_march_1322').
noun(edwardIV).
noun(henryVI).
noun(palm_Sunday).
noun(richard_of_york).
noun('30_December_1490').
noun(war_of_the_roses).
noun(earl_of_newcastle).
noun(fairfax).
noun('30_June_1643').
noun(bradford).
noun(prince_rupert).
noun(marquis_of_newcastle).
noun(fairfax).
noun(oliver_cromwell).
noun('2_June_1644').
noun(battle).
noun(slain).
noun(defeated).
noun(killed).
adj(bloody).
adj(traitorous).
verb(defeats).
verb(was).
det(a).
det(the).
prep(on).
best_match(Subject,Object,Verb):-
history(X,Y),
member(Subject,knowledgebase),
member(Object,knowledgebase),
member(Verb,knowledgebase),
write(X),nl,
fail.
micro_watson:- write('micro_watson: Please ask me a question:'), read(X),
sentence(X,Sentence,Subject,Object,Verb),nl,write(Subject),nl,write(Verb),nl,write(Object).
sentence(Sentence,sentence(Noun_Phrase, Verb_Phrase),Subject,Object,Verb):-
np(Sentence,Noun_Phrase,Rem),
vp(Rem,Verb_Phrase),
nl, write(sentence(Noun_Phrase,Verb_Phrase)),
noun(Subject),
member(Subject,Sentence),
noun(Object),
member(Object,Rem),
verb(Verb),
member(Verb,Rem),
best_match(Subject,Object,Verb).
member(X,[X|_]).
member(X,[_|Tail]):-
member(X,Tail).
np([X|T],np(det(X),NP2),Rem):-
det(X),
np2(T,NP2,Rem).
np(Sentence,Parse,Rem):- np2(Sentence,Parse,Rem).
np(Sentence,np(NP,PP),Rem):-
np(Sentence,NP,Rem1),
pp(Rem1,PP,Rem).
np2([H|T],np2(noun(H)),T):-noun(H).
np2([H|T],np2(adj(H),Rest),Rem):- adj(H),np2(T,Rest,Rem).
pp([H|T],pp(prep(H),Parse),Rem):-
prep(H),
np(T,Parse,Rem).
vp([H|[]],verb(H)):-
verb(H).
vp([H|T],vp(verb(H),Rest)):-
verb(H),
pp(T, Rest,_).
vp([H|T],vp(verb(H),Rest)):-
verb(H),
np(T, Rest,_).
As i said i had number 2 working until i tried number 3, now it just prints the parsed sentence out and then give me a 'Error: out of local stack message' any help is greatly appreciated! So at the top is the knowledge base with which we are comparing out list to find the best match, these are called (albeit incorrectly at this stage) by the best_match method, which executes immediately after the sentence method which parses the sentence and extract the key words. Also i apologise if the code is terribly laid out!
Cheers
I assume the person who posted this is never coming back, I wanted to remind myself some prolog, so here it is.
There are two major issues with this code, apart from the fact that there are still some logical problems in some predicates.
Problem 1:
You ignored singleton warnings, and they usually are something not to be ignored. The best match predicate should look like this:
best_match(Subject,Object,Verb):-
history(X,Y),
member(Subject,Y),
member(Object,Y),
member(Verb,Y),
write(X),nl,
fail.
The other warning was about the Sentence variable in the sentence predicate, so it goes like this:
sentence(X,Subject,Object,Verb),nl,write(Subject),nl,write(Verb),nl,write(Object).
sentence(Sentence,Subject,Object,Verb):-
np(Sentence,_,Rem),
vp(Rem,_),
nl,
noun(Subject),
member(Subject,Sentence),
noun(Object),
member(Object,Rem),
verb(Verb),
member(Verb,Rem),
best_match(Subject,Object,Verb).
Problem 2:
I assume you divided the np logic into np and np2 to avoid infinite loops, but then forgot to apply this division just where it was necessary. The longest np clause should be:
np(Sentence,np(NP,PP),Rem):-
np2(Sentence,NP,Rem1),
pp(Rem1,PP,Rem).
If you really wanted to allow more complicated np there, which I doubt, you can do it like this:
np(Sentence,np(NP,PP),Rem):-
append(List1,List2,Sentence),
List1\=[],
List2\=[],
np(List1,NP,Rem1),
append(Rem1,List2,Rem2),
pp(Rem2,PP,Rem).
This way you will not end up calling np with the same arguments over and over again, because you make sure that the sentence checked is shorter each time.
Minor issues:
(How the program works, after the infinite loop problem has been fixed)
The last vp is repeated
I am not sure about your grammar, and e.g. why "defeated" is a noun...
Just to check that the program works I used the sentence [edwardIV,defeated,henryVI,on,palm_Sunday].
I changed "defeated" to a verb, and also changed the last vp clause to:
vp([H|T],vp(verb(H),Rest)):-
verb(H),
np(T,_,Rest1),
pp(Rest1, Rest,_).
For the example sentence I got battle_of_Boroughbridge and battle_of_Towton as results.
I know on how to display a list by using loop.
For example,
choice(a):-write('This is the top 15 countries list:'),nl,
loop(X).
loop(X):-country(X),write(X),nl,fail.
Unfortunately, I don't know on how to display list by using list. Anyone can guide me?
it's not very clear what it is that you're trying to achieve.
I'm not sure from your description whether you have quite got to grips with the declarative style of Prolog. When you wrote your rule for loop you were providing a set of conditions under which Prolog would match the rule. This is different from a set of procedural instructions.
If you want to collect all the countries into a list you can use the setof rule like follows
top_countries(Cs):-
setof(C, country(C), Cs).
This will return a list [] of the countries matched by the rule.
If you wanted to output each element of this list on a new line you could do something like the following recursive function.
write_list([]).
write_list([H|T]):-
write(H),nl,
write_list(T).
The first rule matches the base case; this is when there are no elements left in the list. At this point we should match and stop. The second rule matches (unifies) the head of the list and writes it to screen with a newline after it. The final line unifies the tail (remainder) of the list against the write_list function again.
You could then string them together with something like the following
choice(a):-
write('This is the top 15 countries list:'),nl,
top_countries(X),
write_list(X).
Things to note
Try not to have singleton variables such as the X in your choice rule. Variables are there to unify (match) against something.
Look into good declarative programming style. When you use functions like write it can be misleading and tempting to treat Prolog in a procedural manner but this will just cause you problems.
Hope this helps
write/1 doesn't only write strings, it writes any Prolog term. So, though Oli has given a prettier write_list, the following would do the job:
choice(Countries):-write('This is the top 15 countries list:'),nl,write(Countries).