The question of the difference between a functor and a predicate in prolog is asked often.
I am trying to develop an informal definition that is suitable for new students.
A functor is the name of a predicate. The word functor is used when
discussing syntax, such as arity, affix type, and relative priority
over other functors. The word predicate is used when discussing
logical and procedural meaning.
This looks "good enough" to me.
Question: Is it good enough, or is it fundamentally flawed?
To be clear, I am aiming to develop a useful intuition, not write legalistic text for an ISO standard!
The definition in https://www.swi-prolog.org/pldoc/man?section=glossary is:
"functor: Combination of name and arity of a compound term. The term foo(a,b,c) is said to be a term belonging to the functor foo/3." This does not help a lot, and certainly doesn't explain the difference from a predicate, which is defined: "Collection of clauses with the same functor (name/arity). If a goal is proved, the system looks for a predicate with the same functor, then uses indexing to select candidate clauses and then tries these clauses one-by-one. See also backtracking.".
One of the things that often confuses students is that foo(a) could be a term, a goal, or a clause head, depending on the context.
One way to think about term versus predicate/goal is to treat call/1 as if it is implemented by an "infinite" number of clauses that look like this:
call(foo(X)) :- foo(X).
call(foo(X,Y)) :- foo(X,Y).
call(bar(X)) :- bar(X).
etc.
This is why you can pass around at term (which is just data) but treat it as a "goal". So, in Prolog there's no need to have a special "closure" or "thunk" or "predicate" data type - everything can be treated as just data and can be executed by use of the call/1 predicate.
(There are also variations on "call", such as call/2, which can be defined as:
call(foo, X) :- foo(X).
call(foo(X), Y) :- foo(X, Y).
etc.)
This can be used to implement "meta-predicates", such as maplist/2, which takes a list and applies a predicate to each element:
?- maplist(writeln, [one,two,three]).
one
two
three
where a naïve implementation of maplist/2 is (the actual implementation is a bit more complicated, for efficiency):
maplist(_Goal, []).
maplist(Goal, [X|Xs]) :-
call(Goal, X),
maplist(Goal, Xs).
The answer by Peter Ludemann is already very good. I want to address the following from your question:
To be clear, I am aiming to develop a useful intuition, not write legalistic text for an ISO standard!
If you want to develop intuition, don't bother writing definitions. Definitions end up being written in legalese or are useless as definitions. This is why we sometimes explain by describing how the machine will behave, this is supposedly well-defined, while any statement written in natural language is by definition ambiguous. It is interpreted by a human brain, and you have no idea what is in this brain when it interprets it. As a defense, you end up using legalese to write definitions in natural language.
You can give examples, which will leave some impression and probably develop intuition.
"The Prolog compound term a(b, c) can be described by the functor a/2. Here, a is the term name, and 2 is its arity".
"The functor foo/3 describes any term with a name foo and three arguments."
"Atomic terms by definition have arity 0: for example atoms or numbers. The atom a belongs to the functor a/0."
"You can define two predicates with the same name, as long as they have a different number of arguments."
There is also the possibility of confusion because some system predicates that allow introspection might take either a functor or the head of the predicate they work on. For example, abolish/1 takes a functor, while retractall/1 takes the predicate head.....
Related
I am currently trying to understand some Prolog code for a game, but I somehow can't find any documentation about a specific predicate or rule that the programmer used, called 'line'.
He uses it in the argument list of other predicates, but neither is it customly defined by him nor can I find it in any documentation or anywhere else on the internet. I can't even call it seperately in my Prolog interpreter, even though it works perfectly in his code.
Can anyone tell me, what this predicate means or does?
solve([line(_, Line, Constr)|Rest]) :-
(specifically the line(_, Line, Constr) part)
This isn't a predicate, this is a data structure, in Prolog terminology, a compound term. Check out this glossary: https://www.swi-prolog.org/pldoc/man?section=glossary.
You probably have a list of lines, and each line is represented as a triple of values. Based on what you show it is a bit difficult to guess what exactly it contains. The _ in the first argument is the way the programmer says "I don't care about this value".
A compound term is the only non-atomic data structure in Prolog. A list for example is a nested compound term like .(a, .(b, .(c, []))) but the language has built-in functionality to let you write this as [a, b, c].
You can think of compound terms, with their names and arity, as the typed objects of Prolog (but please don't push this analogy too far).
How do I create a predicate that takes another predicate and returns a derived version of it?
For example, pairwise predicates can be fairly mechanically extended to apply to lists:
all_whatever(_, []).
all_whatever(X, [Y|T]) :-
whatever(X, Y),
all_whatever(X, T).
What would be the definition of
pairwise_listwise(whatever, all_whatever).
If it's not possible/common/clunky/violates principles, what would be the alternative pattern?
There are two different ways to achieve what you want. The simplest, and likely preferred, way is to define a meta-predicate that takes any binary predicate and applies it to all elements of the list like so:
listwise(_,_,[]).
listwise(P,Y,[X|Xs]) :-
call(P,Y,X),
listwise(P,Y,Xs).
You can then call this as listwise(whatever, Y1, Xs1) to apply whatever to Y1 and each element of Xs1.
This is made possible thanks to the call/N meta-predicate. Note that this meta-predicate can also take partially constructed goals as first argument, so that an alternative formulation could be:
listwise(_,[]).
listwise(P,[X|Xs]) :-
call(P,X),
listwise(P,Xs).
Which is then called as listwise(whatever(Y1),Xs1). This version of the predicate is actually known as maplist/2 instead of listwise, at least in SWI-Prolog (in module library(apply)) and SICStus Prolog (in module library(lists)).
The second way to achieve what you want (actually closer to what you where asking for) is to actually define a new predicate all_whatever/2 using term expansion. Term expansion is a mechanism to rewrite terms when they are loaded (see e.g. for more details in SWI-Prolog: https://www.swi-prolog.org/pldoc/doc_for?object=term_expansion/2). I am showing here the SWI-Prolog version, which is by defining a clause for the term_expansion/2 predicate. This mechanism works differently in different systems or is altogether missing.
term_expansion(pairwise_listwise(PairPred,ListPred), ExpandedTerm) :-
TerminalCall =.. [ListPred,_,[]],
RecursiveCall =.. [ListPred,Y,[X|Xs]],
SingleCall =.. [PairPred,Y,X],
FinalCall =.. [ListPred,Y,Xs],
ExpandedTerm = [TerminalCall, (RecursiveCall :- (SingleCall, FinalCall))].
In this clause, ExpandedTerm is a list defining the two clauses we want to define and all the terms in it are built from the predicate names using =... One can then define the new predicate as follows:
pairwise_listwise(whatever, all_whatever).
When this code is loaded, that clause will be expanded and replaced by two clauses defining the new predicate all_whatever. And now one can call for instance all_whatever(Y1,Xs1).
My preference goes to the first approach (conceptually simpler and works across Prolog versions) but I think it is also useful to be aware of the existence of the term expansion mechanism as well.
I currently have a small Prolog database containing a few people and some predicates for relations. For example:
female(anna).
female(susan).
male(john).
male(timmy).
siblings(anna, susan).
siblings(anna, john).
siblings(susan, john).
sibling(X, Y) :- siblings(X, Y) ; siblings(Y, X).
%X is brother of Y
brother(X, Y) :- male(X), sibling(X, Y).
and I have a DCG which can determine valid questions like
"who is the brother of john", which also works well.
question --> ip, verb, article, noun, pronoun, name.
Now I want my program to make a call to my family-database out of noun and name like this:
noun(X, name).
Which in the example then should be
brother(X, anna).
and then return the answer as a natural-language answer like:
"the brother of anna is john"
Defining the grammer for the answer sentence is no problem either. The only thing I don't know is, how to make the call from my DCG to my database and to get the right values filled into it. I looked around for quite some time now - perhaps I don't know the right search terms - and couldnt find something related to this.
I hope you guys have some good ideas ! :)
Thank you.
Invoking Prolog predicates from DCGs
Regular way: Use {}/1
Use the nonterminal {}//1 to call arbitrary Prolog goals from within DCGs.
For example:
verb --> [V], { verb(V) }.
This defines a nonterminal verb//1. This DCG describes a list consisting of the element V such that verb(V) holds, where verb/1 is a normal Prolog predicate.
In a sense even more regular: Use DCGs throughout!
Note that there is a second way to do this, which is in a sense even easier to understand: You can simply turn everything into DCG nonterminals!
For example, you could say:
female(anna) --> [].
female(susan) --> [].
male(john) --> [].
male(timmy) --> [].
You could then simply use these nonterminals directly. You could define a term_expansion/2 rule that does such a transformation automatically.
In your specific case, using {}/1 is likely preferable, because you already have existing Prolog facts and. But there are definitely cases where using DCGs throughout is preferable.
EDIT: From your comment, I see your question is a bit more involved.
The question is rather about:
Constructing Prolog goals from sentences
This is extremely straight-forward: Essentially, you only need to describe the relation between the Prolog goals you want and the corresponding sentences.
We do this by introducing a new argument to the DCG, and that argument will denote the Prolog goal that needs to be executed to answer the sentence. In your example, you want to relate the sentence "Who is the brother of susan?", to a call of the Prolog predicate brother(X, susan). You already have a nonterminal sentence//0 that describes such sentences. You only need to make explicit the goal that such sentences correspond to. For example:
sentence_goal(noun(X, name)) --> ip, v, a, noun, p, name.
This is only used to illustrate the principle; I'm not claiming that this is already the full solution. The point is simply to show that you can reason about Prolog goals in exactly the same way as about all other terms.
You can then invoke the actual goals in two phases:
first, relate the given sentence to the goal, using this new nonterminal sentence_goal//1
simply call the goal, using call/1 or invoking it directly.
For example:
?- phrase(sentence_goal(Goal), Sentence), Goal.
In your case, all that remains is relating such sentences to the Prolog goals you want to invoke, such as brother_of/2 etc.
None of this needs any side-effects (write/1)! Instead, concentrate on describing the relations between sentences and goals, and let the Prolog toplevel do the printing for you.
So am being told a specific predicate has to work in +,+ mode. What does that mean in Prolog?
When one wants to give information on a predicate in prolog, those conventions are often used :
arity : predicate/3 means predicate takes 3 arguments.
parameters : predicate(+Element, +List, -Result) means that Element and List should not be free variables and that Result should be a free variable for the predicate to work properly. ? is used when it can be both, # is mentionned on the above answer but is not really used as much (at least in swi-pl doc) and means that the input will not be bound during the call.
so telling that somepredicate works in +, + mode is a shortcut for telling that :
% somepredicate/2 : somepredicate(+Input1, +Input2)
In order to give you a definite answer you need to tell us more than just +,+. For predicates whose arguments are only atoms, things are well defined: p(+,+) means that the predicate should only be called with both arguments being atoms.
But if we have, say lists, things are more complex. There are two meanings in that case. Consider member/2 which succeeds for member(2,[1,2,3]).
Are the queries member(2,[X]) or member(2,[X|Xs]) now +,+ or not?
The direct interpretation which is also used in ISO Prolog says that (quoting 8.1.2.2 Mode of an argument, from ISO/IEC 13211-1:1995):
+ the argument shall be instantiated,
In that sense both queries above are +,+.
However, there is another interpretation which implicitly assumes that we have access to the definition of the predicate. This interpretation stems from the mode declarations of DEC-10 Prolog, one of the first Prolog systems. So lets look at member/2:
member(X, [X|_]).
member(X, [_|Xs]) :-
member(X, Xs).
A mode member(+,+) would now mean that when executing a goal, this mode will hold for all subgoals. That is, member(2,[X]) would be +,+ whereas member(2,[X|Xs]) is not
because of its subgoal member(2,Xs).
People do confuse these notions quite frequently. So when you are talking about lists or other compound terms, it helps to ask what is meant.
For more on modes see this answer.
It means that the arguments to the predicate will both be input arguments (though not pure input).
This page has a succint description of all of Prolog's call modes.
So, let's say I have the following in a Prolog database:
person(john).
person(mary).
happy(john).
It is clear to that if I want to list all people, I can type:
person(X).
But, what if I want to find all the things that are true about john? I cannot do:
X(john).
But the effect I would like is to be able to put in "john" and get back "person" and "happy".
There is clearly another way I could store my information:
is(person, john).
is(person, mary).
is(happy, john).
And then, I can do:
is(X, john).
But I lose some expressiveness here. I really would like to be able to do something like:
X(john).
Any ideas?
Thanks!
Parameterizing a query over predicates (as in finding ∀x over x(...)) is not usually possible natively in PROLOG, as this sort of thing is a second- (or, higher)-order logic operation, whereas PROLOG is based on first-order logic.
There are, however, descriptions of how implementations of higher-order logic functions in PROLOG are possible, at least to a limited extent - there are real uses for such functionality. See The Art Of Prolog, Chapter 16, and Higher-order logic programming in Prolog by Lee Naish.
Hm, from my experience, that's not the typical use case of Prolog. If you want to enumerate all "facts" about John, you would first have to define them as terms, and encode their arity. Then you can use call/N and go down the rabbit hole another notch (from memory with the help of GNU Prolog):
relation(1,person).
relation(2,married).
person(john).
married(john,mary).
? relation(1,X), call(X,john).
X = person
| ?- relation(2,X),call(X,john,Y).
X = married
Y = mary
Note that using call has many interesting issues and potential for runtime errors.
This is an approximation:
all_predicates(Term) :-
current_predicate(_, Pred), %% match Pred to any currently defined predicate
\+ predicate_property(Pred, built_in), %% filter out the built-in predicates
functor(Pred, Name, 1), %% check that Pred has 1 argument and match Name to its name
Goal =.. [Name, Term], %% construct the goal Name(Term)
call(Goal). %% Note that if Pred has side effects, they will happen.