I am new to prolog and was hoping someone could clear this up for me. I want to query if someone is a father. So I wrote the following statements and rules:
man(Joe).
man(Josh).
man(John).
parent(Joe,Josh).
parent(Josh,John).
father(D,K) :- man(D), parent(D,K).
I am confused because when I run the query:
father(Joe,John).
true.
It returns true. Why is this? It seems to be searching though the relations but I have no idea why!
In prolog, strings that start with a capital are variables. When you write parent(Joe,Josh)., you're not defining a relationship between two people Joe and Josh, but you're saying that the parent relationship is true for any values of the variables 'Joe' and 'Josh'.
For the relations to work as expected, you have to either use lower-case atoms (e.g. father(joe,josh).), or use quoted atoms (father('Joe', 'Josh').).
Related
I have the following facts.
loves(ami, paul).
loves(lucy, paul).
female(ami).
artist(ami).
female(lucy).
artist(lucy).
canadian(paul).
lovesCanadianArtists(Person) :- forall(canadian(X), loves(Person, X)).
When I execute the query in SWI-Prolog:
?- lovesCanadianArtists(X).
The answer is true, and I don't get results.
Someone told me that the issue is the predicate isLovedByArtists(Person) is not inversible or invertible. So, I should add a condition on Person variable because it is not bound by the forall\2 predicate. Like:
lovesCanadianArtists(Person) :- female(Person), forall(canadian(X), loves(Person, X)).
So, my questions are:
Is this predicate invertibility documented anywhere ? I can't find it.
For me, the explanation given is wrong, and but I am not sure whether I should get results with my first rule. What's the underlying issue here ?
What's the underlying issue here ?
"forall/2 does not change any variable bindings. [...] If your intent is to create variable bindings, the forall/2 control structure is inadequate." - https://www.swi-prolog.org/pldoc/man?section=forall2
Perhaps one of foreach, findall, bagof or setof will do what you want, although it's not clear from the plural 'artists' and singular 'Person' exactly what that is; e.g. for a list of all People who love at least one Canadian artist, which may have duplicates if you add more Canadian artists:
lovesCanadianArtists(People) :-
findall(Person, (canadian(X), loves(Person, X)), People).
I am writing a Prolog program in which given a set of facts about the citizenship(s) of a person in the following format (meaning [name] is a citizen of a [list of countries]):
citizen(name, [list of countries])
Example: citizen(JaneDone, [Germany, United States])
A query is able to return if a person has citizenship in Germany. I am writing my query like this:
citizenOfGermany(citizenName) :-
member(citizen, citizen(citizenName)).
However, it always returns an empty list no matter what value I feed into citizenName. This seems strange, considering that I thought that the member function checks whether the first parameter is within the second parameter?
You've done a few things wrong. For starters, in Prolog, variables start with Capital letters, and you need to quote atoms that start with capital letters.
So:
citizen('JaneDone', ['Germany', 'United States']).
And in Prolog, there aren't any functions; you need to spell things out with predicates.
So:
citizenOfGermany(CitizenName) :-
citizen(CitizenName, Countries),
member('Germany', Countries).
And let's try it out:
?- citizenOfGermany(C).
C = 'JaneDone' ;
false.
A more fundamental question is: why are you defining your facts as citizen_of_countries/2? Relational databases typically don't have lists, so why are you using a list for a fact? It's better to do this:
citizen_of_country('JaneDone', 'Germany').
citizen_of_country('JaneDone', 'United State').
citizen_of_Germany(CitizenName) :-
citizen_of_country(CitizenName, 'Germany').
and, if you need a list of all citizenships:
citizen_of_countries(Citizen, Countries) :-
setof(Country, citizen_of_country(Citizen, Country), Countries).
(I'll leave it as an exercise as to why bagof/3 could be used instead of setof/3 but findall/3 shouldn't ... hint: what should citizen_of_countries('Unknown Person', Countries) do?)
I'm pretty new to prolog and while learning it I stumbled upon a problem that I'm having. I basically have a few database facts. They are:
book(year(1937), title([of,mice,and,men]), rating_out_of_ten(9)).
book(year(2008), title([the,hunger,games]), rating_out_of_ten(8)).
I'm am trying to query the books that have the word "of" in the title. This is what I attempted:
book(year, title, rating_out_of_ten), member(of, title).
It returns false when I do this. Can someone please help. Thanks in advance.
So I'm new to the prolog too but I think I know the solution:
In your query you are actually using the wrong predicate, it should be book, instead of movie
The query should look like this:
book(X,title(Y),Z), member(of,Y)
Arguments have to be capitalized (they have to be variables), however to reach elements of the list you have to use list's name and then a variable, like this:
title(Y)
so you can use Y in the application of the member predicate.
Remember that variable names must start with a capital letter (or underscore). Also, are you really querying on movie when your facts are book?
You could try:
?- book(year(Y), title(T), rating_out_of_ten(R)), member(of, T).
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)).
first off thanks for helping. I am writing a prolog program describing family relationships, including all versions of in-laws. The logic is all there, what I need help with is some prolog problems as I am not very experienced with it. I am trying to set up multiple possibilities for each rule through use of semicolons.
The way I am treating in-laws is so that my brother in law is also my brother, so I need multiple checks to see which is true. I want prolog to return true, and only true, if any of the options are true. However, it returns true and false as possible options, since of course one of the options is always going to be false and the other is always going to be true. Either they are my brother in law, or my natural brother. I cant get prolog to return true only, and not have the option of false as another answer. If anyone has any advice it would be great. Relevant code is included below. So, if I type "brother(baby,dad)." I get true and false as possible answers when all I want is false. However, "brother(dad,baby)." only returns true. But I am rambling now. Sorry if any of the code is confusing with the baby dad stuff. Thanks!
/*facts for relationships*/
female(widow).
female(redhair).
spouse(i,widow).
spouse(widow,i).
spouse(dad,redhair).
spouse(redhair,dad).
child(i,dad).
child(redhair,widow).
child(baby,i).
child(onrun,dad).
male(onrun).
male(baby).
male(dad).
male(i).
/*rules*/
daughter(D,P):-
female(D), (child(D,P);(spouse(P,S),child(D,S))).
son(D,P):-
male(D), (child(D,P);(spouse(P,S),child(D,S))).
mother(X,Y):-
female(X),
child(Y,X).
father(X,Y):-
male(X),
child(Y,X).
son_in_law(C,P):-
male(C),spouse(C,S),
(child(S,P);(spouse(P,W),child(S,W))).
daughter_in_law(C,P):-
female(C),spouse(C,S),
(child(S,P);(spouse(P,W),child(S,W))).
brother(S1,S2) :- male(S1),
(child(S1,P) = child(S2,P2));
(child(S1,P),child(S2,P2),spouse(P,P2));
((child(S1,P),son_in_law(S2,P));(child(S2,P),son_in_law(S1,P))).
These multiple answers can be preventing with the meta-predicate once/1:
?- once(brother(baby,dad)).
true.
?-
thanks for reading. I know its not the easiest to understand. child is above in the set of facts that you see. Child doubles for a test to get parents. So when I pass in brother(baby, dad) the program then calls child(baby,X)=child(dad,X) the child function is being given the child, so it returns the parent. I then check to see if the parents are the same, as that would mean that the two are brothers.