Why predicates and functions are not explicitly separated in Prolog? - prolog

Consider this Prolog program:
a(1).
b(X) :- X.
This is valid in SWI Prolog. And the following queries give desirable (at first glance) results without any warnings:
?- b(a(1)).
true
?- b(a(2)).
false
And then it is unclear for me, why this is allowed.
Fact a(1). says that predicate a/1 is true with argument 1.
Query b(a(1)) asks if predicate b/1 is true with a(1) function value. When this query is resolved, a(1) is checked as predicate, however it was taken from predicate argument context which should allow only terms there.
So different concepts are messed here. We have predicates which may be true or false depending on their arguments. And we have symbolic functions which are some abstract (symbolic) values defined by functor and arguments. The function does not necessary return true or false, it may be completely different domain. The only action with function here might be using it as a term in predicates to state some rules and facts about its value.
For me it looks like rule b(X) :- X. should not be compilable because variable X was firstly used in term context, and then in predicate context. Probably, variables should not be allowed at all in predicate context.
Isn't this some fundamental design inconsistency from math point of view?

Related

functor vs predicate - definition for students

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.....

prolog predicates cf boolean valued functions

Guides teaching prolog are careful to dissuade students from thinking that predicates are functions.
After some thought, the idea that predicates are boolean functions seems valid.
Predicates have zero of finite input parameters, and their output is either true or false, success or fail.
Question: Is this dangerous to think of prolog predicates as boolean valued functions? What are the limitations of this analogy?
The following is the closest I have found to discussing this question meaningfully:
https://www.reddit.com/r/prolog/comments/f48grt/difference_between_predicate_and_function/
You can call predicates boolean functions, but look at this:
?- member(a, [a,b,c]).
true ;
false.
Also this:
?- member(X, [a,b,c]).
X = a ;
X = b ;
X = c.
Functions don't do that as far as I know. "Predicates" as used in procedural languages like C++ and Python are either true of false, once. They are not both true and false, nor are they true three times in a row.
EDIT: I can't tell which one is worse, reddit or stackoverflow. Both are terrible places to learn anything you didn't know already.

Prolog jargon: id(X,X). fact or rule?

In Prolog, this is unambiguously a fact:
foo(bar).
And this is unambiguously a rule:
foo(X) :- bar(X).
But what about a clause that has both non-singleton variables and no :- such as
identity(X,X).
or more realistically something like
my_member(X, [X|_]).
I've been calling these rules since I learned Prolog, but now that I've tried to check to be 100% sure, I can't seem to find any source making a stronger distinction than what I have in the first two examples.
So is a rule:
a clause that defines a variable logical relationship, i.e. a clause that will not always succeed.
a clause that that defines a relationship between predicates (or possibly a predicate and itself).
Sometimes terminology itself causes problems the actual Prolog systems do not have at all. In common terminology as well as standard terminology, both identity(X,X). and my_member(X, [X|_]). are facts. However, better use clause when this seems fit.
The unease stems from the set of solutions that are implied by such cases. In fact, there is an infinity of solutions for both examples. Otherwise, ground facts just describe one solution each. Sticking to ground facts only, simplifies bottom-up interpretations.
So what about the clause a :- true. Is it a fact or a rule? It uses a rule-atom. but it's body is true. A Note in 3.72 excludes (:-)/2 as principal functor of facts. Well, all of this is a clear indication that terminology is here a bit too fine grained.
So, stick as much as you can to clause.
The truth is that there is an argument over Prolog's terminology, but i' ll try to make a brief review which will hopefully lead to some answers.
Generally speaking, a Prolog program consists of objects and the relations between them.
The relations are called predicates and the objects are called arguments of the predicate. The number of the arguments is the predicate's arity.
Describing the objects and their relations is being done with clauses. There are three types of clauses: facts, rules and queries.
A fact denotes a relation between objects. This relation is unambiguously true. Syntactically, a fact consists of a name describing a relation, followed by one or more comma separated objects in parenthesis and a period. Example:
male(john).
father_of(adam, cain).
Combining facts, we can define new relations between objects. This is done with a rule, which consists of two parts: a condition section (also called body of the rule) and a conclusion (also called head of the rule). While facts denote relations that are unambiguously true, rules denote relations that are true only if certain conditions are true. These conditions are also relations between objects. Syntactically, the head of the rule is separated from the body with the neck operator (:-) which can be read as if. The conditions of the rule, if more than one, are separated by commas which can be read as and. Example:
father_of(X,Y) :-
parent(X,Y),
male(X).
In conclusion, rules and facts are clauses. A rule has the form Head :- Body. and a fact has the form Head. Predicates are relations defined by a name and number of arguments and there can be multiple facts or rules for the same predicate. Ultimately:
father_of/2 is a predicate named father_of with arity 2
father_of(adam, cain). is a fact
father_of(adam, abel). is another fact
father_of(A,B) :- parent(A,B), male(A). is a rule

Why is Prolog not recognizing these built-ins?

I'm having trouble using the round/1 and floor/1 built-ins in SWI-Prolog. When using them in my code, they aren't recognized and when submitting them as a query; for instance ?- round(1.6)., Prolog will tell me that the procedure is not recognized. Am I doing something wrong? I tried it on both the online Swish version and my own windows installed version, but getting the same error on both.
round/1 and floor/1 are no builtin predicates, round/2 and floor/2 are.
Prolog works with predicates. That means that a predicate can only be true or false (or error). Furthermore it can unify variables (further).
So the only means to calculate the floor of 1.6, is to use two variables, and make the second one the floor of the first one. For example:
?- round(1.6,X).
X = 2.
?- floor(1.6,X).
X = 1.
Since it is sometimes cumbersome to write predicates that way. Prolog has defined some functors, these functors can be interpreted with the is/2 predicate. round/1 and floor/1 are functors with semantics in the is/2 predicate:
?- X is round(1.6).
X = 2.
?- X is floor(1.6).
X = 1.
is can work with more advanced expression trees as well, like:
?- X is floor(0.4+0.4+0.4).
X = 1.
But note that is is actually a predicate as well. We have written:
is(X, floor(0.4+0.4+0.4)).
behind the curtains, and the is/2 predicate will call floor/2. Mind however that you can not simply inject your own predicate that way. You can not simply write is(X, foo(2)) and expect Prolog to call foo(2.X).

Commutativity of disjunction in Prolog

I've just started learning Prolog and I encountered a problem that I don't understand.
When I ask:
?- fail; true.
Prolog answers:
true
Which is something I expected. But, if I ask:
?- true; fail.
Prolog answers:
true ;
false.
..and I don't understand why. The disjunction operator should be commutative. Why are these two Prolog answers different?
Also note that the Prolog disjunction operator, (;)/2, is not commutative in general. For example:
?- !; write(else).
true.
?- write(then); !.
then
true ;
true.
The right branch of the disjunction is only tried on backtracking if the implicit choice point is not cut when executing the left branch. Note that a clause such as:
foo :- (!; write(else)).
is equivalent to:
foo :- !.
foo :- write(else).
Thus, cuts and (other) side-effects result in (;)/2 not behaving as logical disjunction.
it's just a detail of top level interaction, then you could observe a different behaviour depending on Prolog interpreter you're using.
SWI-Prolog, in introductory documentation, gives some information:
2.1.2 Executing a query
After loading a program, one can ask Prolog queries about the program. The query below asks Prolog what food `sam' likes. The system responds with X = if it can prove the goal for a certain X. The user can type the semi-colon (;) or spacebar6 if (s)he wants another solution. Use the return key if you do not want to see the more answers. Prolog completes the output with a full stop (.) if the user uses the return key or Prolog knows there are no more answers. If Prolog cannot find (more) answers, it writes false.
The confusion regards how prolog displays results. When you make a query in prolog, it will attempt to find all possible answers. That means it will start at the first fact or clause, go through them sequentially and, when it can finally make the query true, displays the answer. If there was a choice point in the process of finding the last solution, prolog prompts the user to seek more possible successful solutions.
In the case of:
?- false ; true.
This query starts by looking at the clause false, which fails and then, since there's a disjunction ;, checks the clause after the ; which is true. This succeeds, and prolog displays:
true
Note that when it found this solution, there were no more choices, so there's no prompt for further solutions.
Now let's look at the second example:
?- true ; false.
Prolog looks at the first clause, true, and succeeds and tells the user:
true
But in this case, it hasn't exhausted all of the possible solutions since there's a disjunction ; that created another choice. So when you enter the ; at the prompt:
true ;
You tell prolog to find more solutions. Prolog goes back and checks the clause after the disjunction and encounters false. This fails and there are no other solutions. Therefore, your request for further solutions fails and prolog outputs false:
true ;
false
The first true means it succeeded. The false means it found no more solutions and failed on the second attempt.
Prolog's behavior is to seek solutions sequentially through the appropriate clauses and present them as long as you ask for them until it fails. When it finally fails, you get false. Some prologs output no. The behavior above is not a commutativity issue.

Resources