The Prolog standard ISO/IEC 13211-1:1995/Cor.2:2012
features compare/3:
8.4.2 compare/3 – three-way comparison
8.4.2.1 Description
compare(Order, X, Y) is true iff Order unifies with R which is one of the following atoms: '=' iff X and Y are identical terms (3.87), '<' iff X term_precedes Y (7.2), and '>' iff Y term_precedes X. [...]
Recently, it dawned on me that using the atoms <, =, and > is somewhat weird:
The predicates (<)/2 and (>)/2 express arithmetic comparison.
The predicate (=)/2 on the other hand is syntactic term unification.
IMHO, a much more natural choice would (have) be(en) #<, == and #>, as these are exactly the predicates whose fulfillment is determined by compare/3.
So: why were the atoms </=/> chosen—and not #</==/#>?
Recently, it dawned on me that using the atoms <, =, and > is somewhat
weird:
The compare/3 predicate existed in several Prolog systems prior to find its way into the ISO Prolog Core standard. The choice here (I was the WG17 Core editor at the time) was to preserve backward compatibility.
compare/3 exists as a built-in since 1982 which is the quasi second edition of the DECsystem 10 manual. The first of 1978 (called User's guide) did not contain compare/3 nor (#<)/2 and related built-ins; only (==)/2 and (\==)/2. The 1982 manual refers in the definition of this built-in to a "standard order". And thus the three symbols (which constitute in the standard the domain order) make quite some sense in that context. The standard itself refers to 7.2 Term order via term_precedes.
Some systems had used == as the symbol for identity, but changed to =. However, I have never encountered #< in any system.
Note that identity of terms is well defined even when considering terms with variables and even infinite trees, whereas the general Term order is only partially defined in such cases.
Related
The numerical comparison operators in prolog are pretty much the same as every other language.
operator
meaning
X > Y
X greater than Y
X < Y
X less than Y
X >= Y
X greater than or equal to Y
X =< Y ( not <= )
X less than or equal to Y
Question: Why did prolog diverge from most other languages and use =< and not <=?
Is the reason to due with how such symbol were written by hand, the explanation often cited for the :- meaning <- implication from right to left.
updated - edited to correct typos
In imperative programming languages, smaller equal is literally written as <=. But in Prolog, <= looks more like an arrow to the left since Prolog is often used to implement various theorem provers. Thus =< was the more natural choice1 for the arithmetical comparison operator.
For arithmetical evaluation and comparison, this is just a little nuisance as a misuse will show up as a harmless syntax error. But it becomes more cumbersome in the context of constraints. The implementation of clpfd by SICStus has both #<= and #=< as infix operators meaning implication and smaller equal respectively which leads to many unnecessary beginners' errors. Note that such errors are very difficult to detect, since many uses like X #<= 1 are valid for both meanings.
Because of this confusion, newer implementations like clpfd for SWI and its successor clpz (for both SICStus and Scryer) use rather #<== and #==> for implication and thus do not define #<= at all.
Note that also other programming languages have to work around this problem. Most notably Haskell uses => for class constraints thus writing the arrow in the other direction since <= is already taken to mean comparison.
1 At least since DEC 10 Prolog of 1978.
The earliest use is probably in the benchmark qsort
on page 54 of Report 40, D.H.D. Warren, Implementing Prolog—Compiling Predicate Logic Programs. May 1977.
partition([X,..L],Y,[X,..L1],L2) :- X =< Y, !,
partition(L,Y,L1,L2).
This ,.. is a | in ISO. The ..-notation is still present in =.. univ.
let's say I have some predicate a/1, now how would I represent b which is true if a fails for some value ?
Unfortunately not doesn't help here , a definition like this :
b(X):- not(a(X)).
means "b is true if for any X a is false"(I want this to work when X isn't instantiated).
How would someone express this ? and what about the general case where more than one (not instantiated) variable exists ?
Is there more known about a/1?
Many Prolog predicates do have purely relational, sound negations.
For example, the unification X = Y can be cleanly stated not to hold by using the constraint dif/2: dif(X, Y) is true iff X and Y are different. It works correctly in all modes of use.
Similarly, CLP(FD) constraints like (#=)/2, (#>)/2 and others all have a completely sound logical negations. For example, you can say X #\= Y to state that X and Y are distinct integers.
A general way to express such issues is to reify the truth values of your predicates. For example, instead of a predicate a/1, consider a predicate a/2, where the second argument denotes whether the predicate holds in this case. You would call this as a(Arg, Truth), and your job is to implement it in such a way that Truth correctly reflects the truth value of a/1 for Arg. You can throw an instantiation_error in cases where you cannot make a sound decision. The preferable way is of course to declaratively express all possible cases using suitable constraints.
In some cases, constraint refication is already available out of the box. For example, you can negate all reifable CLP(FD) constraints using the predicate (#\)/1. Therefore, #\ (X #= Y) is the same as X #\= Y. Boolean constraints provide similar features.
As pointed before, there is no logical negation in Prolog, since there is no closed universe. Prolog negation is a negation-by-failure. This is, something is false whether it can not be prooved to be true.
In practique, not/1 (or '\+'/1) requieres a ground term to behalf as a logical negation.
You may find some experiments with logical negation (closed universes or domains) in some development environments (as far as I remember, Ciao Prolog has something about that). It requieres variables to be declared as having values at some finite domain.
Why is argument precendence of **/2 (xfx) and (^)/2 (xfy) not the same in Prolog?
This causes minor inconsistencies, such as the following:
?- X = 1, Y is 1 ^ -X.
X = Y, Y = 1.
and:
?- Y is 1 ** -1.
Y = 1.
but:
?- X = 1, Y is 1 ** -X.
ERROR: Syntax error: Operator priority clash
ERROR: X = 1, Y is 1 *
ERROR: ** here **
ERROR: * -X .
Minor point: It's (^)/2 and not ^/2 to indicate that ^ is used as an operator and to make it valid Prolog syntax and a predicate indicator (7.1.6.6).
(**)/2 and (^)/2 are both evaluable functors (9), so they can be used for Arithmetic evaluation (8.7) with (is)/2 and Arithmetic comparison (8.7) with (=:=)/2, (<)/2 and the like. Their definitions differ slightly.
(**)/2 always gives back a float in the same way as (/)/2 always gives a float. (SWI does not follow the standard here, it has its own conventions).
?- X is 2**2.
X = 4.0.
?- X is 2/2.
X = 1.0.
(^)/2 is here to permit integer exponentiation which has become much more important with many systems now supporting arbitrarily large integers. Think of 2^2^X. That is, if both arguments are integers, the result is an integer as well, in the same way that (*)/2 handles this case.
?- X is 2^2, Y is 2*2.
X = 4, Y = 4.
?- X is 2.0^2, Y is 2.0*2.
X = 4.0, Y = 4.0.
In those cases where (^)/2 would give a real value with two integer arguments (like 2^ -1), a type error is produced, and then there are more errors for otherwise complex or undefined results.
(^)/2 was used for exponentiation for quite some time.
An early use of the exponentiation operator is in D.H.D. Warren's Thesis of 1977 in the example for symbolic differentiation. (It is at least not mentioned in Philippe Roussel's 1975 manual). Throughout the thesis and the 1978 User's guide, the ~ character is used consistently where one would expect a ^ like in integers are restricted to the range -2~17 to 2~17-1 , ie. -131072 to 131071. The declaration was the following and is unchanged since 1982.
:- op(300, xfy, ~). % 1977
:- op(200, xfy, ^). % 1982 - today
From 1982 on, it was used in quantification of setof/3 and bagof/3 but also as lambdas in natural language parsers. For all these uses it already had the right associativity and priority. As an evaluable functor it was present in several systems.
The first system to use (^)/2 as an evaluable functor meaning power is probably C-Prolog.
Compared to this heritage, the (**)/2 appeared in Prolog relatively late, most probably inspired by Fortran. It was proposed for inclusion (N80 1991-07, Paris papers) shortly before the first Committee Draft (CD 1992). Systems provided it also as exp/2.
(**)/2 has the same priority as (^)/2 but does not have any associativity, which at first might strike as odd, since there are quite some cases, where it is common to have exponentiation twice. Most prominently, the Gaussian function in its simplest form
e-x2
Instead of using the constant e and exponentiation, a special evaluable functor exp/1 is provided. Above is thus written as exp(- X**2). In fact, also Wikipedia uses this notation. Given this functor, there are no needs for associativity in this common case.
Should there actually be one, I would be very interested to see it.
Compared to other systems it seems quite common to offer two kinds of exponentiation. Think of Haskell which has ^ and **.
To conclude: There does not seem to be a frequent case where nested float exponentiation is needed. So minimal support seems to be preferable.
#false answered your first question.
The example you give is due to the following difference:
?- integer(-1).
true.
?- X = 1, integer(-X).
false.
and the following precedences:
?- current_op(X, xfx, **).
X = 200.
?- current_op(X, fy, -).
X = 200.
The reason (not justification) for the inconsistency is that in the original standard from 1995 only **/2 was an arithmetic exponentiation operator, while ^/2 was only used for quantifying variables in bagof/3 and setof/3. For the latter use, it made sense to have right-associativity, so you could write X^Y^foo(X,Y,Z). Why **/2 was not given xfy associativity I don't know (it would have been consistent with Fortran, for instance).
The ^/2 as an exponentiation operator was added in a 2012 "corrigendum", without revising the syntax, leading to the current inconsistency.
But note that you can simply fix this yourself by adding a directive
:- op(200, xfy, **).
This is unlikely to cause any problems. Moreover, in many modern Prologs operator declarations are effective only locally in a module.
Is there any logical difference between these two implementations of a variant predicate?
variant1(X,Y) :-
subsumes_term(X,Y),
subsumes_term(Y,X).
variant2(X_,Y_) :-
copy_term(X_,X),
copy_term(Y_,Y),
numbervars(X, 0, N),
numbervars(Y, 0, N),
X == Y.
Neither variant1/2 nor variant2/2 implement a test for being a syntactic variant. But for different reasons.
The goal variant1(f(X,Y),f(Y,X)) should succeed but fails. For some cases where the same variable appears on both sides, variant1/2 does not behave as expected. To fix this, use:
variant1a(X, Y) :-
copy_term(Y, YC),
subsumes_term(X, YC),
subsumes_term(YC, X).
The goal variant2(f('$VAR'(0),_),f(_,'$VAR'(0))) should fail but succeeds. Clearly, variant2/2 assumes that no '$VAR'/1 occur in its arguments.
ISO/IEC 13211-1:1995 defines variants as follows:
7.1.6.1 Variants of a term
Two terms are variants if there is a bijection s of the
variables of the former to the variables of the latter such that
the latter term results from replacing each variable X in the
former by Xs.
NOTES
1 For example, f(A, B, A) is a variant of f(X, Y, X),
g(A, B) is a variant of g(_, _), and P+Q is a variant of
P+Q.
2 The concept of a variant is required when defining bagof/3
(8.10.2) and setof/3 (8.10.3).
Note that the Xs above is not a variable name but rather (X)s. So s is here a bijection, which is a special case of a substitution.
Here, all examples refer to typical usages in bagof/3 and setof/3 where variables happen to be always disjoint, but the more subtle case is when there are common variables.
In logic programming, the usual definition is rather:
V is a variant of T iff there exists σ and θ such that
Vσ and T are identical
Tθ and V are identical
In other words, they are variants if both match each other. However, the notion of matching is pretty alien to Prolog programmers, that is, the notion of matching as used in formal logic. Here is a case which lets many Prolog programmers panic:
Consider f(X) and f(g(X)). Does f(g(X)) match f(X) or not? Many Prolog programmers will now shrug their shoulders and mumble something about the occurs-check. But this is entirely unrelated to the occurs-check. They match, yes, because
f(X){ X ↦ g(X) } is identical to f(g(X)).
Note that this substitution replaces all X and substitutes them for g(X). How can this happen? In fact, it cannot happen with Prolog's typical term representation as a graph in memory. In Prolog the node X is a real address somehow in memory, and you cannot do such an operation at all. But in logic things are on an entirely textual level. It's just like
sed 's/\<X\>/g(X)/g'
except that one can also replace variables simultaneously. Think of { X ↦ Y, Y ↦ X}. They have to be replaced at once, otherwise f(X,Y) would shrink into f(X,X) or f(Y,Y).
So this definition, while formally perfect, relies on notions that have no direct correspondence in Prolog systems.
Similar problems happen when one-sided unification is considered which is not matching, but the common case between unification and matching.
According to ISO/IEC 13211-1:1995 Cor.2:2012 (draft):
8.2.4 subsumes_term/2
This built-in predicate provides a test for syntactic one-sided unification.
8.2.4.1 Description
subsumes_term(General, Specific) is true iff there is a
substitution θ such
that
a) Generalθ
and Specificθ are identical, and
b) Specificθ and Specific
are identical.
Procedurally, subsumes_term(General, Specific) simply
succeeds or fails accordingly. There is no side effect or
unification.
For your definition of variant1/2, subsumes_term(f(X,Y),f(Y,X)) already fails.
Because Prolog uses chronological backtracking(from the Prolog Wikipedia page) even after an answer is found(in this example where there can only be one solution), would this justify Prolog as using eager evaluation?
mother_child(trude, sally).
father_child(tom, sally).
father_child(tom, erica).
father_child(mike, tom).
sibling(X, Y) :- parent_child(Z, X), parent_child(Z, Y).
parent_child(X, Y) :- father_child(X, Y).
parent_child(X, Y) :- mother_child(X, Y).
With the following output:
?- sibling(sally, erica).
true ;
false.
To summarize the discussion with #WillNess below, yes, Prolog is strict. However, Prolog's execution model and semantics are substantially different from the languages that are usually labelled strict or non-strict. For more about this, see below.
I'm not sure the question really applies to Prolog, because it doesn't really have the kind of implicit evaluation ordering that other languages have. Where this really comes into play in a language like Haskell, you might have an expression like:
f (g x) (h y)
In a strict language like ML, there is a defined evaluation order: g x will be evaluated, then h y, and f (g x) (h y) last. In a language like Haskell, g x and h y will only be evaluated as required ("non-strict" is more accurate than "lazy"). But in Prolog,
f(g(X), h(Y))
does not have the same meaning, because it isn't using a function notation. The query would be broken down into three parts, g(X, A), h(Y, B), and f(A,B,C), and those constituents can be placed in any order. The evaluation strategy is strict in the sense that what comes earlier in a sequence will be evaluated before what comes next, but it is non-strict in the sense that there is no requirement that variables be instantiated to ground terms before evaluation can proceed. Unification is perfectly content to complete without having given you values for every variable. I am bringing this up because you have to break down a complex, nested expression in another language into several expressions in Prolog.
Backtracking has nothing to do with it, as far as I can tell. I don't think backtracking to the nearest choice point and resuming from there precludes a non-strict evaluation method, it just happens that Prolog's is strict.
That Prolog pauses after giving each of the several correct answers to a problem has nothing to do with laziness; it is a part of its user interaction protocol. Each answer is calculated eagerly.
Sometimes there will be only one answer but Prolog doesn't know that in advance, so it waits for us to press ; to continue search, in hopes of finding another solution. Sometimes it is able to deduce it in advance and will just stop right away, but only sometimes.
update:
Prolog does no evaluation on its own. All terms are unevaluated, as if "quoted" in Lisp.
Prolog will unfold your predicate definitions as written and is perfectly happy to keep your data structures full of unevaluated uninstantiated holes, if so entailed by your predicate definitions.
Haskell does not need any values, a user does, when requesting an output.
Similarly, Prolog produces solutions one-by-one, as per the user requests.
Prolog can even be seen to be lazier than Haskell where all arithmetic is strict, i.e. immediate, whereas in Prolog you have to explicitly request the arithmetic evaluation, with is/2.
So perhaps the question is ill-posed. Prolog's operations model is just too different. There are no "results" nor "functions", for one; but viewed from another angle, everything is a result, and predicates are "multi"-functions.
As it stands, the question is not correct in what it states. Chronological backtracking does not mean that Prolog will necessarily backtrack "in an example where there can be only one solution".
Consider this:
foo(a, 1).
foo(b, 2).
foo(c, 3).
?- foo(b, X).
X = 2.
?- foo(X, 2).
X = b.
So this is an example that does have only one solution and Prolog recognizes that, and does not attempt to backtrack. There are cases in which you can implement a solution to a problem in a way that Prolog will not recognize that there is only one logical solution, but this is due to the implementation and is not inherent to Prolog's execution model.
You should read up on Prolog's execution model. From the Wikipedia article which you seem to cite, "Operationally, Prolog's execution strategy can be thought of as a generalization of function calls in other languages, one difference being that multiple clause heads can match a given call. In that case, [emphasis mine] the system creates a choice-point, unifies the goal with the clause head of the first alternative, and continues with the goals of that first alternative." Read Sterling and Shapiro's "The Art of Prolog" for a far more complete discussion of the subject.
from Wikipedia I got
In eager evaluation, an expression is evaluated as soon as it is bound to a variable.
Then I think there are 2 levels - at user level (our predicates) Prolog is not eager.
But it is at 'system' level, because variables are implemented as efficiently as possible.
Indeed, attributed variables are implemented to be lazy, and are rather 'orthogonal' to 'logic' Prolog variables.