问题
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 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 write repeatedly every feature of every object.
回答1:
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.
回答2:
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 ?
回答3:
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).
回答4:
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).
回答5:
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.
回答6:
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).
来源:https://stackoverflow.com/questions/32852148/how-to-list-all-predicates-that-has-an-specific-atom