Not in Prolog and use of Bagof - prolog

I have database like this:
movie(matrix,wachowski,thriller).
movie(terminator, cameron, thriller).
movie(Gladiator, scott, costume).
movie(star wars, lucas, fantasy).
movie(star trek, abrams, fantasy).
And I want to know who direct fantasy film except Abrams.
I suppose I need to use 'not' predicate, but I don't know exactly how it works.
?- movie(X,not(abrams),fantasy).
But unfortunately it doesn't work.
One more query is what kind of films is not a thriller:
?- movie(X,_,not(thriller)).
Still not working.
Next problem is I need to use predicate direct(Director, listsOfMovie) based on bagof.
?- direct(Director, listsOfMovie) :- bagof(Director,movie(Director,listsOfMovie,_), listsOfMovie).
Still without success :(
Anyone can help?

Use of not
You can't use Prolog predicates like functions. not/1 is a predicate which accepts a query as an argument. So this isn't doing what you think:
movie(X,not(abrams),fantasy).
This is querying movie with a second argument of not(abrams). You don't have any facts or predicates that match movie(_, not(_), _) so it will always fail.
If you want to know which films were not thrillers, you might render it:
movie(X, _, Type),
Type \= thriller.`
Using not, it might be:
not( movie(X, _, thriller) ).
If you wanted the syntax of movie(_, not(_), _) to work, you could write a predicate for it:
movie( Name, not(Director), Type ) :-
movie(Name, D, Type),
D \= Director.
Now we have either a fact or a predicate head that matches the form, movie(_, not(_), _), and then the query, movie(X, not(abrams), Y) would work. But it's not normally done this way.
Using bagof/3
Let's look at your use of bagof. In the simplest case, bagof is supposed to take three arguments:
bagof(X, {query involving X}, ListOfSatisfingXs)
So bagof will run the {query involving X} generating each X that makes it true, creating ListOfSatisfingXs, a unique, sorted list of such instantiations of X. In other words, ListOfSatisfingXs is the unique, sorted values of X that make {query involving X} succeed.
In your case, you've gotten the arguments to bagof a bit mixed up:
direct(Director, listsOfMovie) :-
bagof(Director, movie(Director, listsOfMovie, _), listsOfMovie).
Here, you're reusing your Director argument as your bagof argument, which is not good (since it's not intended). Since you're looking for a list of movies, the first argument should represent the movie. Your query to movie is using listsOfMovie, your intended target argument to hold the list result, which it shouldn't. And finally, listsOfMovie is an atom, not a variable, since it doesn't start with a capital letter.
The corrected version would be:
director_movies(Director, ListOfMovies) :-
bagof(Movie, movie(Director, Movie, _), ListOfMovies).
Here, the bagof is getting the *Unique, sorted list of Movie values such that movie(Director, Movie, _) is true and providing that resulting list in ListOfMovies.

Related

Representing truth regarding beliefs in prolog

How to make this (or something similar) work in Prolog:
belief(john,red(apple)).
belief(peter,red(apple)).
X :- belief(john,X), belief(peter,X).
And get true. for the following query (while consulting above):-
?- red(apple).
First, it's useful to define a little helper to capture when all (relevant) persons believe something:
all_believe(Belief) :-
belief(john, Belief),
belief(peter, Belief).
Then you can define, for example:
red(Object) :-
all_believe(red(Object)).
green(Object) :-
all_believe(green(Object)).
And with your given set of beliefs you get:
?- red(apple).
true.
?- green(apple).
false.
This works. It requires you to define similar rules for any term that you want to use as a belief.
You can make this a bit shorter with macro definitions using term_expansion:
term_expansion(declare_belief(Belief),
Belief :- all_believe(Belief)).
This means that every top-level definition in your source code of the form declare_belief(Belief) should be treated as if you had written Belief :- all_believe(Belief) instead (with the variable Belief substituted appropriately).
So now you can just write this:
declare_belief(red(_)).
declare_belief(green(_)).
and it will be treated exactly like the longer definitions for red(Object) and red(Object) above. You will still have to write this kind of declaration for any term that you want to use as a possible belief.
Prolog does not allow the head of a rule to be just a variable. The head must be a nonvar term, whose functor (i.e., name and arity) identifies the predicate being defined. So, a possible solution would be something like this:
true_belief(X) :-
belief(john, X),
belief(peter, X).
belief(john, red(apple)).
belief(peter, red(apple)).
Examples:
?- true_belief(red(apple)).
true.
?- true_belief(X).
X = red(apple).

How to get rid of Singleton variables errors?

I'm supposed to implement a little prolog program out of the Monty Python movie where the people are arguing whether a woman is a witch. Based on what the say, witches are burned, but wood is also burned, and wood floats, but ducks also float, so, if someone weighs the same as a duck, she's made of wood, therefore, she's a witch.
Based on that, I've come up with this:
witch(X) :- burns(X), female(X).
burns(X) :- wooden(X).
wooden(X) :- floats(X).
floats(X) :- sameWeight(duck, X).
female(X).
sameweight(duck, X).
But when I want to check if X is a witch, by trying witch(X). It actually prints "true", confiming the woman is a witch, but I also get a Singleton variables: [X] error message. So clearly I have a bug somewhere and I would like to fix it.
Those are warnings. It specifies that you use a variable once in clause. This is the case for X in:
female(X).
sameweight(duck, X).
Now this is rather "odd". Variables are typically used for passing values from head to body, or between two predicate calls in the body. But here you only use X once.
In Prolog one uses an underscore (_) if you "do not care" about the value. The underscore is an "anonymous variable": if you use two underscores in the same clause, those are two different variables.
So you can fix it like:
female(_).
sameweight(duck, _).
Note that now you have written that everything is a female, and that everything has the same weight as a duck.

Transform in meta-predicate at prolog

I have been reading and noticed that predicates like call are called meta-predicates and they can return other predicates as a result (Don't know if return is a good use of the word here) for example here:
assert(call(goal, X,Y)).
Edit: lurker called me to reason, this doesn't work.
I understand that it's not supposed to call predicates functions but is there a way of making assert over a predicate that will be unknown until runtime?
I want to use the same insertion predicate for more than one fact , so assert(fact(X)) does not suit my needs. I can retrieve the fact's name on runtime but how could i use assert without unifying a fact directly?
You should explicitly use assertz/1 or asserta/1. assert/1 is an alias for assertz/1 but only in some Prolog systems.
The call:
assertz(call(goal, X, Y)).
will attempt to assert a fact with functor call. This is what it tries to assert in the database:
call(goal, _, _).
Since call is a functor already defined in Prolog as a predicate, it will generate an error. If you were to assert, say, the following:
assertz(foo(goal, X, Y)).
It would be successful, but what you'd get in the database is something like this:
foo(goal, _, _).
Which doesn't seem very useful. In other words, the assert is just doing what you asked it: asserting a term that you just described whose functor is call or foo in the above cases.
If you want to assert an actual predicate, you just need to use the fact that a predicate is a term whose functor is :-. The general predicate term would be something like Head :- Body or, in canonical form, ':-'(Head, Body). This kind of term can be asserted, as long as at least Head is instantiated before the assertz call.
assertz(':-'(Head, Body)).
Or equivalently (since :- is an operator):
assertz((Head :- Body)).
If I do this:
Head = goal, assertz((Head :- Body)).
I get (using listing/0):
:- listing.
goal :-
call(_).
Not very useful. So Body really should be instantiated before making this assertz/1 call. Here then is another example:
Head = double(X, Y), Body = (Y is X * 2), assertz((Head :- Body)).
Which now results in the following:
:- listing.
double(A, B) :-
B is A * 2.

Prolog (Sicstus) - setof and findall combination issues

Given a set of routes a given station has, such us :
route(TubeLine, ListOfStations).
route(green, [a,b,c,d,e,f]).
route(blue, [g,b,c,h,i,j]).
...
I am required to find names of lines that have a specific station in common. The result must be ordered, with non-repeated stations and must return an empty list, if there were no results. So, querying
| ?- lines(i, Ls).
Should give:
Ls = [blue,red,silver] ? ;
no
I tried doing the following:
lines(X, L) :- setof(L1, findall(W, (route(W, Stations),member(X, Stations)),L1), L).
However, it gives the following as an answer:
Is = [[blue,silver,red]];
no
So unordered with double braces. I tried using just findall, but the result is not ordered. I know I could then write sort function and pass that through, however I was wondering if it is possible to use just findall and setof in this instance?
Actually, it's easier than your attempt, but you need to grasp the peculiar setof' behaviour wrt free variables, and account for the eventuality that an unknown station was required (setof/3 fails if there are no solutions).
lines(X, Ls) :-
setof(L, Stations^(route(L, Stations), member(X, Stations)), Ls)
-> true ; Ls = [].
An easier alternative, as you said, use findall/3 exactly as you're doing (without setof!), and sort the output.

Convert list into functor parameter

I got stuck to implement a logic. At some instance in my program I have a list say named as List.
The length of this List is variable and I don't know in advance. Now I have to pass this list in a functor to create a fact and I am unable to implement it. For eg:
if List is [first] then it should add the fact functor(first).
if List is [first,second] then it should add the fact functor(first,second).
if List is [first,second,third] then it should add the fact functor(first,second,third).
and so on...
I was trying by =.. but here I am unable to map that variable length constraint. For fixed length I am able to perform but I don't know in advance that how many elements will be there in list.
Any suggestions to implement this logic. Thanks.
I don't quite understand your problem with =.. but this worked for me:
assert_list(List) :-
Term =.. [my_functor|List],
assert(Term).
Note that I use my_functor instead of simply functor because functor/3 is a built-in predicate so you cannot assert ternary functor facts (functor(first, second, third)).
Calling it:
?- assert_list([first,second,third]).
true.
Checking that it works:
?- listing(my_functor).
:- dynamic user:my_functor/3.
user:my_functor(first, second, third).
true.
Note that technically, the different n-ary my_functor/n predicates are not the same predicates. You must use different queries in your program for each n. To circumvent this, you could simply assert the list as one and only argument of my_functor:
?- List = [first, second, third],
assert(my_functor(List)).
true.
?- listing(my_functor).
:- dynamic user:my_functor/3.
user:my_functor([first, second, third]).
true.
My SWI-Prolog version is 5.7.5.

Resources