简体   繁体   中英

Predicates with =.. operator in Prolog

Last time I learnt about =.. that can translate a list to term and opposite. I have 3 predicates to do, first one is the one that translates a list to a term. I came up with sth like this:

list_to_term(List, Functor, Term) :-
    Term =.. [Functor | List].

Is it okey? Enough? Or I miss something?

The other predicate is count(A,T,N) for element A, in term T with number N that is true if N is a count of elements A in term T... Can anyone help me with this one or how to start?

 ?- count(a,f(a),N).
 N = 1
 ?- count(a,f(a,g(b,a),N).
 N = 2.
 ?- count(a,f(a,g(X,a),N).
 N = 2.

Looking at the answer of this post you can reuse the predicate flatten_term/2 , a little bit modified to handle free variables, to sove your problem. Here is the code for a basic solution:

flatten_term(Term,[Term]):-
    (atomic(Term);var(Term)),!.
flatten_term(Term,Flat):-
    Term =.. TermList,
    flatten_term_list(TermList,Flat),!.

flatten_term_list([],[]):-!.
flatten_term_list([H|T],List):-
    flatten_term(H,HList),
    flatten_term_list(T,TList),
    append(HList,TList,List),!.

occurrences(_,[],N,N):-!.
occurrences(A,[H|T],N,Tot):-
    A \== H,!,
    occurrences(A,T,N,Tot).
occurrences(A,[H|T],N,Tot):-
    A == H,!,
    N1 is N+1,
    occurrences(A,T,N1,Tot).

count(A,Term,N):-
    flatten_term(Term,Flatten),
    occurrences(A,Flatten,0,N).

?- count(a,f(a,g(X,a),d),T).
T = 2.

?- count(X,f(a,g(X,a),d),T).
T = 1

First of all you flatten the term using flatten_term/2 . Then simply count the occurrences of the element you want to find using occurrences/4 . You can, if you want, modify flatten_term/2 to avoid the usage of occurrences/4 and so scan the term (list) only one time... Something like: flatten_term(Term,Flatten,ElementToFind,Counter,Total) .

Start by solving a more general problem of counting the terms in a list . Processing a term is processing a singleton list containing that term, after all:

count(A,T,N):- count(A, [T|Z],Z, 0,N).

count(_, [],  [], C,N):- N is C, !.
count(A, [T|B],Z, C,N):- ?=(A,T), A=T, !, count(A, B,Z, C+1,N).
count(A, [T|B],Z, C,N):- ?=(A,T), T=..[_|S], !, append(S,Y,Z), count(A, B,Y, C,N).
count(A, [_|B],Z, C,N):- count(A, B,Z, C,N).

This opens up each head term in a list in succession and appends its argument terms to that list thus using it as a queue ... thus processing the predicate's second argument T in a breadth-first manner.

This assumes A argument is an atom, and ?= is used to avoid instantiating the free variables we might encounter, and instead to skip over them, as your examples seem to indicate.

Is it okey? Enough? Or I miss something?

Prolog's =../2 predicate [swi-doc] can "pack" and "unpack" a list that contains the functor name and its arguments in a term and vice versa. So one can use this to construct a term, or to analyze a term. For example:

?- f(a,g(b,a)) =.. L.
L = [f, a, g(b, a)].

Here f is the functor name, and a and g(b, a) are the arguments. These arguments can be terms as well, and then we thus need to unpack these arguments further.

We can for example obtain all the subterms of a term with:

subterms(T, T) :-
    \+ var(T).
subterms(T, ST) :-
    \+ var(T),
    T =.. [_|As],
    member(A, As),
    subterms(A, ST).

For example:

?- subterms(f(a,g(X,a)),N).
N = f(a, g(X, a)) ;
N = a ;
N = g(X, a) ;
N = a ;
false.

Now that we obtained all (sub)terms, we can slightly rewrite the predicate to count the number of elements that match:

subterm_query(Q, T) :-
    Q == T.
subterm_query(Q, T) :-
    \+ var(T),
    T =.. [_|As],
    member(A, As),
    subterm_query(Q, A).

so we obtain if we query for a :

?- subterm_query(a, f(a,g(X,a))).
true ;
true ;
false.

If we can use the aggregate library , we can make use of the aggregate_all/3 predicate to count the number of times, the predicate was succesful:

?- aggregate_all(count, subterm_query(a, f(a,g(X,a))), Count).
Count = 2.

If not, you need to implement a mechanism that returns 1 for a match, and sums up recursively the matches of the child terms. I leave this as an exercise.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM