How to list all predicates that has an specific atom?

梦想与她 提交于 2019-11-30 18:50:01

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!