Compile time testfor 'atoms' - prolog

Completely new to prolog. Interesting journey so far in trying to change how I think, so appreciate any help here.
I am trying to assert facts for a pre-defined set of names. For example, assume I have a a set of people [alice, bob, ...] in one file. I would like to assert facts about these folks in other files, but want to make sure that these folks exist and that is checked when the facts are loaded/compiled(?).
For example, assume I don't have 'chuck' in the list and I make an assertion:
user: swipl app.pl
?- full_name(chuck, "Charlie Steel").
should result in an error.
What is the best way I can do this?

So, here's the code I came up with:
person(deborah).
person(tony).
read_my_file(Filename) :-
open(Filename, read, In),
read_my_file1(In),
close(In).
read_my_file1(In) :-
read(In, Term),
( Term == end_of_file
-> true
; assert_or_abort(Term),
read_my_file1(In)
).
assert_or_abort(Term) :-
( full_name(Person, Name) = Term
-> ( person(Person)
-> assertz(full_name(Person, Name))
; format(user, '~w is not a person I recognize~n', [Person])
)
; format(user, '~w is not a term I know how to parse~n', [Term])
).
The trick here is using read/2 to obtain a Prolog term from the stream, and then doing some deterministic tests of it, hence the nested conditional structure inside assert_or_abort/1. Supposing you have an input file that looks like this:
full_name(deborah, 'Deborah Ismyname').
full_name(chuck, 'Charlie Steel').
full_name(this, has, too, many, arguments).
squant.
You get this output:
?- read_my_file('foo.txt').
chuck is not a person I recognize
full_name(this,has,too,many,arguments) is not a term I know how to parse
squant is not a term I know how to parse
true.
?- full_name(X,Y).
X = deborah,
Y = 'Deborah Ismyname'.

Related

Ask Prolog for predicates of an argument [duplicate]

another way to ask the question is:
How I can list all the properties of an atom?
For example:
movie(agora).
director(agora, 'Alejandro Amenabar')
duration(agora, '2h').
so, I will like to receive all the predicates that has agora for argument. In this case it will be: movie, director, duration, with the other parameters ('Alejandro Amenabar', '2h').
I found: this, and this questions, but I couldn't understand well.
I want to have the value of false in the "variable Answer" if PersonInvited doesn't like something about the movie.
My query will be:
answer(Answer, PersonInvited, PersonWhoMadeInvitation, Movie)
Answer: I don't like this director
answer(false, PersonInvited, PersonWhoMadeInvitation, Movie):-
director(Movie, DirectorName),not(like(PersonInvited,DirectorName)).
The same thing will happen with any property like genre, for example.
Answer: I don't like this genre
answer(false, PersonInvited, PersonWhoMadeInvitation, Movie):-
genre(Movie, Genre), not(like(PersonInvited,Genre)).
So, I want to generalize this situation, instead of writing repeatedly every feature of every object.
I found two solutions the 2nd is cleaner from my point of view, but they are different.
Parameters:
PredName: Name of the predicate.
Arity: The Arity of the Predicate.
ParamValue: If I want to filter by one specific parameter.
PosParam: Which is the position of the parameter in the predicate.
ListParam: All the value of the posibles values parameters (mustbe a Variable all the time).
Solution 1:
filter_predicate(PredName, Arity, ParamValue,PosParam, ListParam):-
current_predicate(PredName/Arity),
Arity >= PosParam,
nth(PosParam, ListParam, ParamValue),
append([PredName], ListParam, PredList),
GlobalArity is Arity + 1,
length(PredList, GlobalArity),
Predicate =.. PredList,
Predicate.
Query
filter_predicate(PredName, Arity, agora, 1, Pm).
Output
Arity = 2
Pm = [agora,'Alejandro Amenabar']
PredName = director ?
yes
Solution2:
filter_predicate(PredName, Arity, ParamList):-
current_predicate(PredName/Arity),
append([PredName], ParamList, PredList),
GlobalArity is Arity + 1,
length(PredList, GlobalArity),
Predicate =.. PredList,
Predicate.
Query 1:
filter_predicate(PredName, Arity, [agora, X]).
Output
Arity = 2
PredName = director
X = 'Alejandro Amenabar' ?
Query 2:
filter_predicate(PredName, Arity, [X, 'Alejandro Amenabar']).
Output
Arity = 2
PredName = director
X = agora ?
here is my attempt, using SWI-Prolog
?- current_predicate(so:F/N), N>0, length(As,N), Head =.. [F|As], clause(so:Head,Body), As=[A|_], A==agora.
note that I coded into a module called so the facts, so I qualify with the module name the relevant calls. Such builtins (clause/2 and current_predicate/1) are ISO compliant, while modules (in SWI-prolog) are not. So I'm not sure about portability, etc...
clause/2 it's a builtin that allows for easy writing metainterprets. See the link for an awesome introduction to this Prolog historical 'point of strength'.
The 2 last calls (I mean, As=[A|_], A==agora) avoid matching clauses having a variable as first argument.
Using reading lines into lists with prolog
All your predicates are in a file 'my_file.pl'.
e.g. my_file.pl contains:
movie(agora).
director(agora, 'Alejandro Amenabar').
duration(agora, '2h').
You can use:
getLines(File,L):-
setup_call_cleanup(
open(File, read, In),
readData(In, L),
close(In)
).
readData(In, L):-
read_term(In, H, []),
( H == end_of_file
-> L = []
; L = [H|T],
readData(In,T)
).
pred_arg_file(Pred,Argue,File):-
getLines(File,L),
member(M,L),
M=..List,
member(Argue,List),
List=[Pred|_].
Then you can query:
?-pred_arg_file(Pred,agora,'my_file.pl').
Pred = movie ;
Pred = director ;
Pred = duration ;
false
or
?- findall(Pred,pred_arg_file(Pred,agora,'my_file.pl'),Preds).
Preds = [movie,director,duration].
If you want to return the properties, return the whole List not just the head.
pred_arg_file(List,Argue,File):-
getLines(File,L),
member(M,L),
M=..List,
member(Argue,List).
From my understanding you should change your data representation so that you can query the relations.As other answers have pointed out, So use triples, you can easily write code to change all your relations into this form as a one off. You then need to work out what the best way to store likes or dislikes are. This will effect how negation works. In this example:
relation(starwars,is,movie).
relation(lucas, directs,starwars).
relation(agora, is,movie).
relation('Alejandro Amenabar', directs, agora).
relation(agora, duration, '2h').
like(ma,'Alejandro Amenabar').
like(ma,movie).
like(ma,'2h').
ma_does_not_want_to_go(Film):-
relation(Film,is,movie),
relation(Film,_,Test), \+like(ma,Test).
ma_does_not_want_to_go(Film):-
relation(Film,is,movie),
relation(Test,_,Film), \+like(ma,Test).
ma_wants_to_go(Film):-
relation(Film,is,movie),
\+ma_does_not_want_to_go(Film).
sa_invites_ma(Film,true):-
ma_wants_to_go(Film).
sa_invites_ma(Film,false):-
ma_does_not_want_to_go(Film).
A draft of a solution using Logtalk with GNU Prolog as the backend compiler:
% a movie protocol
:- protocol(movie).
:- public([
director/1,
duration/1,
genre/1
]).
:- end_protocol.
% a real movie
:- object('Agora',
implements(movie)).
director('Alejandro Amenabar').
duration(120).
genre(drama).
:- end_object.
% another real movie
:- object('The Terminator',
implements(movie)).
director('James Cameron').
duration(112).
genre(syfy).
:- end_object.
% a prototype person
:- object(person).
:- public([
likes_director/1,
likes_genre/1
]).
:- public(likes/1).
likes(Movie) :-
conforms_to_protocol(Movie, movie),
( Movie::genre(Genre),
::likes_genre(Genre) ->
true
; Movie::director(Director),
::likes_director(Director) ->
true
; fail
).
:- end_object.
% a real person
:- object(mauricio,
extends(person)).
likes_director('Ridlye Scott').
likes_genre(drama).
likes_genre(syfy).
:- end_object.
Some sample queries:
$ gplgt
...
| ?- {movies}.
...
(5 ms) yes
| ?- mauricio::likes('Agora').
true ?
yes
| ?- mauricio::likes(Movie).
Movie = 'Agora' ? ;
Movie = 'The Terminator' ? ;
no
| ?- 'The Terminator'::director(Director).
Director = 'James Cameron'
yes
The code can be improved in several ways but it should be enough to give you a clear idea to evaluate this solution.
If I understood your question properly I propose the follow:
What if you change your schema or following this idea you can make a method that simulate the same thing.
class(movie, agora).
property(director, agora, 'Alejandro Amenabar').
property(duration, agora, '2h').
If do you want the types of agora, the query will be:
class(Type, agora)
If you want all the properties of agora, that will be:
property( PropertyName, agora, Value).

Learn Prolog now: Why answering true to the first query of exercise 1.5?

I have just started learning Prolog, and I'm wondering about the first question of this exercise.
%% Suppose we are working with the following knowledge base:
wizard(ron).
hasWand(harry).
quidditchPlayer(harry).
wizard(X) :- hasBroom(X), hasWand(X).
hasBroom(X) :- quidditchPlayer(X).
How does Prolog respond to the following queries?
wizard(ron). -> true
witch(ron). -> undefined procedure
wizard(hermione). -> false
witch(hermione). -> undefined procedure
wizard(harry). -> true
wizard(Y). -> Y = ron ; Y = harry.
witch(Y). -> undefined procedure
Using swipl on Ubuntu, importing the knowledge base for this exercise, first of course trying to decipher what Prolog will returns, and finally checking by myself.
Ok pretty boring stuff until now, I have seen a few answer to these exercises over Github (here, here and there), and I don't understand the answer to the first one: %% 1. wizard(ron). -> true.
First of all the interpreter is complaining about the two definition of what is a wizard:
Warning: /tmp/prolog/ex15.pl:4:
Clauses of wizard/1 are not together in the source-file
Earlier definition at /tmp/prolog/ex15.pl:1
Current predicate: quidditchPlayer/1
Use :- discontiguous wizard/1. to suppress this message
Secondly, when querying I obtain:
?- wizard(ron).
true ;
false.
The way I get it, first Prolog returns the first fact from the knowledge base, then apply the rule head and find out that ron has neither a broom nor a wand.
All this leading to my question: what subtlety have I missed that makes others writing true as an answer to this query?
what subtlety have I missed that makes others writing true as an answer to this query?
`?- wizard(ron).`
true;
false
You have the clause (fact) wizard(ron). in your KB.
To make the things clearer you can write the fact also as the rule clause:
wizard(ron) :- true.
As you can see this is pretty redundant notation but useful in some cases as the general fact representation.
So your query can be interpreted as follows:
Is there an wizard called ron?
Since you have the fact wizard(ron) :- true.
Prolog will first unify the goal and the head.
In your case unify is trivial comparison because no variables are in the goal and the head.
Then Prolog tries to prove body. The body is builtin predicate true, so you quickly get the answer - true.
Then pressing ';' you initiate the search for the alternative solution.
Since no (more) solutions exist for the query wizard(ron), Prolog writes false.
The dot operator designates the clause end. So you wrongly typed dots in your examples:
-> operator means if-then-else relation. It can be used within clause body.
For example you can write std_member/2 as if_member/2
std_member(X, [ X | _ ]).
std_member(X, [ _ | Xs ]) :-
std_member(X, [ _ | Xs).
if_member(X, [ Y | Xs ]) :-
X = Y -> true;
if_member( X, Xs ).

Prolog (Sicstus) - nonmember and setof issues

Given following facts:
route(TubeLine, ListOfStations).
route(green, [a,b,c,d,e,f]).
route(blue, [g,b,c,h,i,j]).
...
I am required to find all the pairs of tube Lines that do not have any stations in common, producing the following:
| ?- disjointed_lines(Ls).
Ls = [(yellow,blue),(yellow,green),(yellow,red),(yellow,silver)] ? ;
no
I came up with the below answer, however it does not only give me incorrect answer, but it also does not apply my X^ condition - i.e. it still prints results per member of Stations lists separately:
disjointed_lines(Ls) :-
route(W, Stations1),
route(Z, Stations2),
setof(
(W,Z),X^
(member(X, Stations1),nonmember(X, Stations2)),
Ls).
This is the output that the definition produces:
| ?- disjointed_lines(L).
L = [(green,green)] ? ;
L = [(green,blue)] ? ;
L = [(green,silver)] ? ;
...
I believe that my logic relating to membership is incorrect, however I cannot figure out what is wrong. Can anyone see where am I failing?
I also read Learn Prolog Now chapter 11 on results gathering as suggested here, however it seems that I am still unable to use the ^ operator correctly. Any help would be appreciated!
UPDATE:
As suggested by user CapelliC, I changed the code into the following:
disjointed_lines(Ls) :-
setof(
(W,Z),(Stations1, Stations2)^
((route(W, Stations1),
route(Z, Stations2),notMembers(Stations1,Stations2))),
Ls).
notMembers([],_).
notMembers([H|T],L):- notMembers(T,L), nonmember(H,L).
The following, however, gives me duplicates of (X,Y) and (Y,X), but the next step will be to remove those in a separate rule. Thank you for the help!
I think you should put route/2 calls inside setof' goal, and express disjointness more clearly, so you can test it separately. About the ^ operator, it requests a variable to be universally quantified in goal scope. Maybe a concise explanation like that found at bagof/3 manual page will help...
disjointed_lines(Ls) :-
setof((W,Z), Stations1^Stations2^(
route(W, Stations1),
route(Z, Stations2),
disjoint(Stations1, Stations2)
), Ls).
disjoint(Stations1, Stations2) :-
... % could be easy as intersection(Stations1, Stations2, [])
% or something more efficient: early fail at first shared 'station'
setof/3 is easier to use if you create an auxiliary predicate that expresses the relationship you are interested in:
disjoint_routes(W, Z) :-
route(W, Stations1),
route(Z, Stations2),
disjoint(Stations1, Stations2).
With this, the definition of disjointed_lines/1 becomes shorter and simpler and no longer needs any ^ operators:
disjointed_lines(Ls) :-
setof((W, Z), disjoint_routes(W, Z), Ls).
The variables you don't want in the result of setof/3 are automatically hidden inside the auxiliary predicate definition.

Prolog error in loop

I would need help about Prolog.
I posted my code, the problem is that i do not obtain the expected result.
I want planning actions for moving on table all blocks until is possible. To do this I prompt :
?- do(while(some(x, block(x) & -onTable(x)),pi(x,putOnTable(x))),s0,S).
I expect to see a response like :
S = do(putOnTable(e), do(putOnTable(b), do(putOnTable(c), s0)))
but Prolog returns "false" only. Someone can help me??
% Golog interpreter
%:- [golog_swi].
:- discontiguous clear/2, on/3, onTable/2.
:- op(800,xfy,[&]).
do(E,S,do(E,S)):- primitive_action(E),poss(a,S).
% Primitive Action Declarations.
primitive_action(putOn(_,_)).
primitive_action(putOnTable(_)).
poss(putOn(X,Y),S) :- clear(X,S), clear(Y,S), \+ on(X,Y,S), \+ X=Y.
poss(putOnTable(X),S):- clear(X,S), \+(onTable(X,S)).
% Successor State Axioms.
on(X,Y,do(A,S)):- A = putOn(X,Y); on(X,Y,S), \+ (A = putOnTable(X); A = putOn(X,_)).
onTable(X,do(A,S)) :- A = putOnTable(X); onTable(X,S), \+ A= putOn(X,_).
clear(X,do(A,S)) :- on(Y,X,S), (A = putOn(Y,_) ; A = putOnTable(Y)); clear(X,S), \+ A = putOn(_,X).
% Restore suppressed situation arguments
restoreSitArg(onTable(X),S,onTable(X,S)).
restoreSitArg(on(X,Y),S,on(X,Y,S)).
restoreSitArg(clear(X),S,clear(X,S)).
block(X):- member(X,[a,b,c,d,e]).
% iniTial COndition
onTable(a,s0).
on(b,a,s0).
on(c,b,s0).
clear(c,s0).
onTable(d,s0).
on(e,d,s0).
clear(3,s0).
thank you!!!
Your predicate do/3 cannot succeed because the goal primitive_action/1 will fail with your query.
Currently, while/2 is not described in primitive_action/1 and it seems it is missing also from your program. So you need to extend primitive_action/1 by further facts, or add a new rule to do/3. And in addition to that you need to describe what while/2 means.
This question is actually about Golog. Your mistake is pretty mundane: you didn't copy the Golog interpreter code into your source file/directory.
Golog defines a number of high-level programming constructs, including while-loops and non-deterministic picks (pi), used here. I'm sure you don't want to reinvent Golog, so just go and get it. I'm assuming that your question is part of an assignment of sorts, and your teacher probably pointed you to the Golog interpreter. Otherwise, you can always find it on the pages of the cognitive robotics group at the Univ. of Toronto: http://www.cs.toronto.edu/cogrobo/main/systems/index.html

Can I subtitude functor with variable in a predicate

I am new to prolog, and using BProlog.
I have been reading some example program to execute query on group of related data. But in order to infer from facts with similar structure, they wrote many predicates like search_by_name,search_by_point, which are partly duplicated.
% working search in example
search_by_name(Key,Value) :-
Key == name,
sname(ID,Value),
point(ID,Point),
write(Value),write(Point),nl.
And when I try to replace them with a more general version like this:
% a more general search I want to write
% but not accepted by BProlog
search_by_attr(Key,Value) :-
Key(ID,Value),
sname(ID,Name),
point(ID,Point),
write(Name),write(Point),nl.
error arised:
| ?- consult('students.pl')
consulting::students.pl
** Syntax error (students.pl, 17-21)
search_by_attr(Key,Value) :-
Key<<HERE>>(ID,Value),
sname(ID,Name),
point(ID,Point),
write(Name),write(Point),nl.
1 error(s)
Am I doing it the wrong way, or is such subtitution impossible in prolog?
code and example data can be found at https://gist.github.com/2426119
I don't know any Prolog that accept variables functors.
There is call/N, or univ+call/1.
search_by_attr(Key,Value) :-
call(Key, ID, Value), % Key(ID,Value)
...
or
search_by_attr(Key,Value) :-
C =.. [Key, ID, Value], % univ
call(C), % Key(ID,Value)
...

Resources