Whats wrong with this version of functor(Prolog)? - 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.

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.

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.

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

Converting Terms to Atoms preserving variable names in YAP prolog

Is there a way to configure YAP (and/or SWI prolog) so they will preserve variable names in any call to term_to_atom/2 ?.
For example, when I execute this:
term_to_atom(member(X, [1,2]), A).
I obtain this answer:
A = 'member(_131405,[1,2])'
Where X has been replaced by its internal representation.
However, I would like to get this answer instead:
A = 'member(X,[1,2])'
Thanks for any help!
There are two issues involved. How to get the variable name X into the system, and how to get a term with such a variable into the atom.
The X you type in is read by the top level which converts it to a regular variable which does not have a name associated. Let's see that in YAP:
?- read(Term).
|: X+3*Y+X.
Term = _A+3*_B+_A
The |: is YAP's prompt for input. And we have entered X+3*Y+X. However, the variable Term contains _A and _B (names chosen by the top level) in place of X and Y. So the information is lost and cannot be restored once it is read by read/1.
You have to access that information differently with the more general built-in for reading read_term/2,3 and the option variable_names/1.
?- read_term(T,[variable_names(Eqs)]).
|: X+3*Y+X.
Eqs = ['X'=_A,'Y'=_B],
T = _A+3*_B+_A
So the read option variable_names/1 gives you the information to restore the variable names. For each named variable read by read_term/2 there is a structure Name = Variable where Name is an atom representing the variable name. Above, 'X' is the name capital X.
Anonymous variables, that is variables whose name is _, do not occur in the list of variable names. They can be rapidly extracted like so:
?- read_term(T,[variable_names(Eqs)]),
term_variables(Eqs, Named),
term_variables(Named+T, Vars),
append(Named, Anons, Vars).
So much for the reading.
Now for the writing. We cannot write the term directly but have to accompany it with the list Eqs. Let's call the new predicate term_to_atom(Term, Eqs, Atom). In both YAP and SWI there is with_output_to(Output, Goal) which writes the output of Goal to different destinations like atom(A). So you can now use write_term/2 to write the term as you please. An example:
?- with_output_to(atom(A),write_term('a b'+X,[quoted(true)])).
A = '\'a b\'+_131284'.
The variable _131284 looks very ugly. To get variables associated with their names for printing we can implement term_to_atom/3 as follows:
term_to_atom(T, Eqs, A) :-
with_output_to(atom(A), write_term(T,[variable_names(Eqs),quoted(true)]) ).
And use it like so:
?- read_term(T,[variable_names(Eqs)]), term_to_atom(T, Eqs, Atom).
|: X+3*Y+X.
Atom = 'X+3*Y+X',
Eqs = ['X'=_A,'Y'=_B],
T = _A+3*_B+_A
variable_names/1 exists as a write option in ISO, Minerva, Jekejeke, GNU, B, SWI, YAP, and SICStus.
In SICStus, the originator of writing terms to lists, one writes:
:- use_module(library(codesio)).
term_to_atom(T, Eqs, Atom) :-
write_term_to_codes(T, Codes, [variable_names(Eqs),quoted(true)]),
atom_codes(Atom, Codes).
The following was an ISO incompatible work around for YAP prior to 6.3.4. It is no longer necessary. As for the differences to a separate write option: term_to_atom/3 as defined below interferes with constraints and does not correctly render '$VAR'/1.
But for the moment we can only approximate the ideal option
variable_names/1. To print terms with our own variable names,
variables have to be substituted in YAP by '$VAR'(Codes) where
Codes is a list of character codes. This does not do exactly the
same, but it is very close. This goes into a file:
:- use_module(library(apply)).
:- use_module(library(lambda)).
write_eqs_term(T, Eqs) :-
\+ \+ (
maplist(\Eq^( Eq = (N='$VAR'(Chs)), atom_codes(N,Chs)), Eqs),
write_term(T,[numbervars(true),quoted(true)])
).
term_to_atom(T, Eqs, A) :-
with_output_to(atom(A), write_eqs_term(T, Eqs) ).
For SWI, you would have to replace atom_codes(N,Chs) by N = Ch.
and install library(lambda) first. It's pre-installed in YAP.

Resources