what is the difference between a predicate and a functor in prolog? - prolog

The following is an example of prolog.
likes(mary,X) :- yellow(X).
According to the definitions I've found (LPN, Bratko, AoP) the likes fits the definition of a predicate and a functor.
yellow also fits the definitions. If the clause were a simple fact (empty body), eg yellow(banana). , that would appear to make no difference.
Question: What is the difference between a predicate and a functor, in the context of prolog, if any?

functor is used to describe terms syntactically: likes(mary,X) is a term that has an arity of 2 and a primary functor likes. The functor is written likes/2 because it is a couple of a name and an arity. Note that likes/2 is also a term, written in an infix way:
?- functor(likes(a,b),F,A).
F = likes,
A = 2.
?- functor(likes/2,F,A).
F = (/),
A = 2.
An atom is a term of arity 0:
?- functor(banana, F, A).
F = banana,
A = 0.
Now, terms in Prolog can be used to describe data or to define procedures. When you write S = person(Name, Age), the functor of S is person/2, it is not ground because it contains unbound variables. By itself, it is just a data structure. However, you can also try to call it in a query:
?- S = person(Name, Age), call(S).
The above is equivalent to:
?- person(Name, Age).
But unless you defined such a predicate, you will encounter an error.
You can write predicates as follows in your source code:
person(Name, Age) :-
date_of_birth(Name, Date),
age_now(Date, Age).
The body of the clause can also be trivially true:
person(john, 20) :- true.
In which case it is a fact, also written:
person(john, 20).
See also term from The Prolog Dictionary.

Related

Is there a Prolog name for atom/1 or stream/1 etc (SWI-Prolog)

Just made a funny observation. SWI-Prolog allows other things than
atom as a functor in a compound. For example it allows me to do:
/* atom as functor */
?- Y =.. [foo, bar].
Y = foo(bar).
/* stream as functor */
?- current_input(X), Y =.. [X, bar].
X = <stream>(0000000069066420),
Y = <stream>(0000000069066420)(bar).
I wonder whether there is a name for what is allowed as a functor,
i.e atom or stream etc.. . The error message by SWI-Prolog doesn't
tell me what is the name, it says it expects an atom:
?- Y =.. [1, bar].
ERROR: Type error: `atom' expected, found `1' (an integer)
But as can be seen a stream etc.. , which is accepted, is not an atom:
?- current_input(X), atom(X).
false.
What is the umbrella type for what SWI-Prolog accepts as functor?
P.S. My guess why this is allowed: It is for example used for Dicts,
dicts are compounds with a special functor C'dict'.
Edit 10.09.2021:
I first thought its simple/1. But simple/1 is reserved
for atom or var, according to this answer:
What is the meaning of predicate "simple/1" in Prolog (SWI-Prolog)
In SWI-Prolog, blobs (binary large objects) are used to store arbitrary binary data, including atoms, images, and stream handles. Particularly, a blob represening a stream handle is a unique symbol which has no syntactical representation (although it is outputted as <stream>(hex-number)).
The built-in predicate blob/2 can be used to get the type of a blob:
?- X = foo, blob(X,Y).
X = foo,
Y = text.
?- current_input(X), blob(X,Y).
X = <stream>(0000000069057160),
Y = stream.
Thus, I think the type accepted as functor in SWI-Prolog is blob.
In Dogelog Runtime we recently introduced a new type tester called symbol/1. One can imagine that it is bootstrapped from blob/2 as follows:
symbol(X) :- blob(X, _).
Dogelog Runtime does also accept symbols as functors, similar like SWI-Prolog. This is used to inline disjunction and if-then-else, and could have further optimization use cases. Functors are not only restricted to atoms, they can be atoms or references:
/* Dogelog Runtime, 0.9.6 */
?- current_input(X), atom(X).
fail.
?- current_input(X), Y =.. [X, bar].
X = [object Object], Y = [object Object](bar).
But I am currently thinking about extending (=..)/2 even more. Namely to allow a compound as functor. What should a compound as functor do? Very simple:
/* Expected Result */
?- X =.. [foo(bar), baz].
X = foo(bar, baz)
So (=..)/2 would add the arguments to the given compound. This further extension of (=..)/2 doesn't need a new data type in the compound functor, but rather changes its behaviour.
It would have a couple of use cases:
Old Higher Order:
Bootstrapping apply/2 would be as easy as:
apply(X,L) :- G =.. [X|L], G.
New Higher Order:
Bottstrapping call/n would be as easy as:
call(X,Y) :- G =.. [X,Y], G.
call(X,Y,Z) :- G =.. [X,Y,Z], G.
call(X,Y,Z,T) :- G =.. [X,Y,Z,T], G.
Etc..
DCG Expansion:
Expanding a non-terminal by an input and output list would be only a matter of calling (=..)/2. Here is an example:
?- G =.. [np(X),I,O].
G = np(X,I,O).

Get result of operator predicate in Prolog

I am trying to understand operators.
I have defined the following operator and method for it.
:- op(600, xfy, ⧺).
⧺(Left, Right) :- concatAtoms([Left, Right], _). % _ would the result but can´t be returned without an extra parameter
% concatenates atoms, e.g. [a,b] = ab
concatAtoms([H|T], R) :-
concatAtoms(T, H, R).
concatAtoms([], R, R).
concatAtoms([H|T], Atom, R) :-
atom_concat(Atom, H, Res),
concatAtoms(T, Res, R).
The query
?- a⧺b.
returns true as expected.
Is there any way for it to return
ab
instead (which was computed by the concatAtoms predicate)?
Maybe I'm completely wrong, but ...
:- op(600, xfy, ⧺).
defines syntax only.
(btw, ⧺ (the double plus is not the same as #)
?- atom_codes('⧺#',L).
L = [10746, 35].
After syntax has been defined, we can write terms like this:
?- X=a⧺b⧺c⧺d, write_canonical(X).
⧺(a,⧺(b,⧺(c,d)))
X = a⧺b⧺c⧺d.
So much for syntax and term structure, but what is the meaning of the above, in the sense of, what should it evaluate to, if it should evaluate to anything?
We evidently need an interpreter for terms like ⧺(a,⧺(b,⧺(c,d))).
If we want, we can call it ⧺, the Prolog parser should be able to distinguish a ⧺ in predicate position and one in operator position.
The interpreter predicate takes a 2-arity term with functor ⧺ and relates it to an evaluation result, or fails, or throws an exception.
Here is a (semi-bad) representation:
⧺(⧺(L,R), Result) :- atom(L),\+atom(R),!, ⧺(R, Tmp), atom_concat(L,Tmp,Result).
⧺(⧺(L,R), Result) :- \+atom(L),atom(R),!, ⧺(L, Tmp), atom_concat(Tmp,R,Result).
⧺(⧺(L,R), Result) :- atom(L),atom(R) ,!, atom_concat(L,R,Result).
We have now linked syntax to semantics, or at least some form of (cheap) semantics:
?- ⧺(a⧺b⧺c⧺d, R).
R = abcd.
Now you just have to know when to call ⧺/2. This depends on what the program wants to do.
In an elegant scenario, one would be able to extend "arithmetic function evaluation trigger" is/2 to have the above things on the right-hand side of is interpreted, as in R is a⧺b⧺c⧺d., but I don't think that's possible.

How to tell Prolog that two literals are equivalent

Anyone knows how to tell Prolog that n(n(p)) and n(p) represent the same thing?
Or how to reduce n(n(p)) to n(p)?
Anyone knows how to tell Prolog that n(n(p)) and n(p) represent the same thing?
Prolog's unification system has a clear meaning of when two things are the same. n(n(p)) and n(p) are not the same thing. You can construct a predicate that defines a more generic equivalence relation than (=)/2.
Normally in Prolog two constants are different if they have a different name. Two compound terms are the same only if the functor is the same (the name of the functor and the number of parameters), and the parameters are equal as well.
We thus can define a predicate like:
equiv_(n(n(p)), n(p)).
equivalence(L, R) :-
equiv_(L, R).
equivalence(L, R) :-
equiv_(R, L).
equivalence(L, L).
If you the match with equivalence(n(n(p)), n(p)), it will return true.
#false Can't I define a predicate n(n(p)) that returns n(p). What I want, in fact, is that all occurrences of the within a list to be replaced with the latter.
You can make a predicate that unifies a second parameter with n(p) if the first one is n(n(p)):
replace_nnp(X, n(p)) :-
X == n(n(p)).
replace_nnp(X, X) :-
X \== n(n(p)).
Then we can use maplist/3 [swi-doc] to map a list of items to another list of items:
replace_nnp_list(LA, LB) :-
maplist(replace_nnp, LA, LB).
For example:
?- replace_nnp_list([n(n(p)), p, n(p), n(n(p))], X).
X = [n(p), p, n(p), n(p)] ;
false.

Define a predicate "run(....)" in prolog

I am trying to define a predicate looks like "run(ABC, DE)" where
ABC is the functor of one of the predicates and DE is its component.
run(ABC, DE) :- ....................
ab(ff).
cc(dd).
ee(ll).
Basically, I am trying to choose ABC as a functor that I want to choose in the database and get the value of DE as its component.
For example,
?- run(ab, DE).
DE = ff.
Help plz
Using the univ (=..) operator you can split a term in a list of its components, check this post
?- funtor(Term1, Term2)=..List.
List = [funtor, Term1, Term2].
?- ab(ff) =.. List2.
List2 = [ab, ff].
?- member(X, [a,b,c]) =.. List3.
List3 = [member, X, [a,b,c]].
Now, all you need to do is create a predicate that will evaluate any list of term, lets call it meta:
meta(L):- Term =.. L, Term.
Now, in your query, you must pass the term with the same syntax used by the univ operator, where the first element of the list is the funtor of the clause you want to evaluate, and the rest of the elements in the list are the arguments for that funtor.
?- meta([ab, X]).
X = ff.

Matching tuples in Prolog

Why does Prolog match (X, Xs) with a tuple containing more elements? An example:
test2((X, Xs)) :- write(X), nl, test2(Xs).
test2((X)) :- write(X), nl.
test :-
read(W),
test2(W).
?- test.
|: a, b(c), d(e(f)), g.
a
b(c)
d(e(f))
g
yes
Actually this is what I want to achieve but it seems suspicious. Is there any other way to treat a conjunction of terms as a list in Prolog?
Tuple term construction with the ,/2 operator is generally right-associative in PROLOG (typically referred to as a sequence), so your input of a, b(c), d(e(f)), g might well actually be the term (a, (b(c), (d(e(f)), g))). This is evidenced by the fact that your predicate test2/1 printed what is shown in your question, where on the first invocation of the first clause of test2/1, X matched a and Xs matched (b(c), (d(e(f)), g)), then on the second invocation X matched b(c) and Xs matched (d(e(f)), g), and so on.
If you really wanted to deal with a list of terms interpreted as a conjunction, you could have used the following:
test2([X|Xs]) :- write(X), nl, test2(Xs).
test2([]).
...on input [a, b(c), d(e(f)), g]. The list structure here is generally interpreted a little differently from tuples constructed with ,/2 (as, at least in SWI-PROLOG, such structures are syntactic sugar for dealing with terms constructed with ./2 in much the same way as you'd construct sequences or tuple terms with ,/2). This way, you get the benefits of the support of list terms, if you can allow list terms to be interpreted as conjunctions in your code. Another alternative is to declare and use your own (perhaps infix operator) for conjunction, such as &/2, which you could declare as:
:- op(500, yfx, &). % conjunction constructor
You could then construct your conjunct as a & b(c) & d(e(f)) & g and deal with it appropriately from there, knowing exactly what you mean by &/2 - conjunction.
See the manual page for op/3 in SWI-PROLOG for more details - if you're not using SWI, I presume there should be a similar predicate in whatever PROLOG implementation your'e using -- if it's worth it's salt :-)
EDIT: To convert a tuple term constructed using ,/2 to a list, you could use something like the following:
conjunct_to_list((A,B), L) :-
!,
conjunct_to_list(A, L0),
conjunct_to_list(B, L1),
append(L0, L1, L).
conjunct_to_list(A, [A]).
Hmm... a, b(c), d(e(f)), g means a and (b(c) and (d(e(f)) and g)), as well list [1,2,3] is just a [1 | [2 | [3 | []]]]. I.e. if you turn that conjuction to a list you'll get the same test2([X|Xs]):-..., but difference is that conjunction carries information about how that two goals is combined (there may be disjunction (X; Xs) as well). And you can construct other hierarchy of conjunctions by (a, b(c)), (d(e(f)), g)
You work with simple recursive types. In other languages lists is also recursive types but they often is pretending to be arrays (big-big tuples with nice indexing).
Probably you should use:
test2((X, Y)):- test2(X), nl, test2(Y).
test2((X; Y)). % TODO: handle disjunction
test2(X) :- write(X), nl.

Resources