Transform in meta-predicate at prolog - 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.

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).

SWI-Prolog: How to use my own predicate as a condition in when/2

I am trying to implement a Prolog program that can interact with java. To do this I use JPL as the Prolog/Java interface.
I am looking for a mechanism that allows me to execute actions automatically when the conditions become true.
The conditions are also represented by predicates. I have tried to use the predefined predicate "when/2", the problem is that as specified in the documentation here, the condition must be one of these:
nonvar(X)
ground(X)
?=(X, Y)
(Cond1, Cond2)
(Cond2; Cond2)
The last two conditions seem the ones I should use, but I could not make them work.
What do I need to change to make make my own conditions ?
Please, consider J as a local Prolog variable here.
:- use_module(library(jpl)).
:- use_module(library(when)).
should_engage(J) :-
jpl_get(J, 'shouldEngage', V),
V==true,
jpl_get(J, 'players', P),
jpl_call(P, 'canSeeEnemies', [], R),
R==true,
jpl_get(J, 'weaponry', W),
jpl_call(W, 'hasLoadedWeapon', [], R),
R==true.
call_java(J) :-
jpl_call(J, 'stateEngage', [], R).
when(should_engage(X), call_java(X)).
When/1 is part of the coroutining infrastructure that triggers actions on variable instantiation. It uses attributed variables in the background. So, if your J
is normally a variable that can get bound at some time you can do
...,
when(nonvar(X), propagate(X)).
propagate(X) :-
should_engage(X),
call_java(X).
Or
propagate(X) :-
( should_engage(X)
-> call_java(X)
; true
).
The first version will cause the instantiation of X to fail if should_engage/1 fails. The latter version not.
If it is not the binding of a variable that may make should_engage/1 true you'll need to find some other trigger or possibly have a thread that monitors the environment at intervals and propagates.
Note that calling non-logical constructs from when/1 typically makes little sense because Prolog's computation may backtrack, unbinding X and rebinding it again to the same or a different value and thus your propagation may be called many times with
different or the same value.

Accepting 2 different colors, but not the same colors

I'm trying out an exercise where I have to write the predicate, colors/2 (or colors(C1,C2) :- ...) that runs like the following:
?- colors(red,blue).
true.
?- colors(red,red).
false.
?- colors(blue,blue).
false.
So, essentially, I have to write my predicate in a manner where it doesn't accept when you enter the same color twice.
I am defining my facts to be:
col(red,blue).
col(purple,orange).
col(green, yellow).
I am making my predicate to be:
colors(X,Y) :- (col(X,Y); col(Y,X)) not (col(X,X); col(Y,Y)).
I don't understand why my predicate won't work. It is returning a syntax error with "Operator Expected." I am saying that it doesn't matter in what order you write the facts. Meaning, you can say colors(red,blue) or colors(blue,red), but you can't query colors with the same name without it returning false.
I would like to know:
Why this isn't a valid expression.
What I can do to fix the problem.
A couple of things:
You're missing a comma (,) before not and not/1 expects a single term in parentheses, so use more parentheses:
colors(X,Y) :- (col(X,Y); col(Y,X)), not( (col(X,X); col(Y,Y)) ).
As #PauloMora indicated, not/1 is deprecated in favor of the ISO \+/1, so better would be:
colors(X,Y) :- (col(X,Y); col(Y,X)), \+ (col(X,X); col(Y,Y)).
Then looking at col(X,X) and col(Y,Y), there are no facts or predicates where col(X,X) would be true (both arguments are the same). So each of these will always be false, and \+ (col(X,X); col(Y,Y)) will always be true. So the expression is superfluous, and your predicate becomes (at least with the pattern established in your current set of facts):
colors(X,Y) :- col(X,Y) ; col(Y,X).
Since you don't have any facts stipulated with matching colors (col(x,x)), then queries like col(red, red) will fail anyway.
Per the recommendation by #false, for an integrity check on equality of X and Y, the appropriate mechanism would be dif(X, Y):
colors(X, Y) :- (col(X, Y) ; col(Y, X)), dif(X, Y).
The parentheses are desired since , has higher precedence than ;. This would guard against the case where you happened to have a fact or predicate col/2 in which both arguments were the same (identical or unified).

Not in Prolog and use of Bagof

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.

Whats wrong with this version of functor(Prolog)?

I tried to write functor inbuilt in Prolog. This is my version:
lenlist(L,N) :- lenlist(L,0,N).
lenlist([],N,N).
lenlist([_|T],P,N) :- P1 is P+1 , lenlist(T,P1,N).
functor1(Term,F,N) :- Term =.. [F|Args] , lenlist(Args,N).
Here is a sample execution of Prolog inbuilt functor
?- functor(Term,f,6).
Term = f(_G247, _G248, _G249, _G250, _G251, _G252)
Now if I execute the same query with functor1 I get an exception
?- functor1(Term,f,6).
ERROR: =../2: Arguments are not sufficiently instantiated
Exception: (8) _G180=..[f|_G248] ? creep
What's wrong with the functor1 function I wrote?
starblue is correct, but in order to write your version of functor1/3 properly, I recommend that you consider the 'modes' it requires:
Inspect an existing term (i.e., not a variable) for it's functor/arity.
Build a term (assigning it to a variable) from a functor/arity description.
All other modes are irrelevant/incorrect.
With these three cases in mind, try the following. First, case (1): extract the Functor and Arity from an existing Term:
functor1(Term, Functor, Arity) :-
\+ var(Term), !,
% inspect existing term
Term =.. [Functor|ArgList],
length(ArgList, Arity).
Note that we exclude other cases if the Term argument is not a variable with the cut (!). Secondly, case (2): construct a Term from a Functor and an Arity:
functor1(Term, Functor, Arity) :-
var(Term),
atom(Functor),
number(Arity), !,
% build a term
length(ArgList, Arity),
Term =.. [Functor|ArgList].
Note that the mode checking performed by the subgoals prior to the cut (!) encapsulate the guard (precondition) for this case. Finally, all other cases (i.e., those where we need to construct a term, but don't have a functor, arity or either) are invalid (3):
functor1(_Term, _Functor, _Arity) :-
throw('Arguments are not sufficiently instantiated.').
Alternatively, for this last case, this whole clause can be omitted to achieve the behavior that functor/1 returns false for the remaining argument bindings it will cover.
Also note that this version relies on built-ins length/2, var/1, number/1 and atom/1 (among others), which are present in SWI-PROLOG.
The problem is that Args is not yet instantiated for =.. . Try putting lenlist/3 before it.
BTW, you could also use the built-in length/2.

Resources