Related
Say we were to execute the following, and SWI Prolog responds:
?- write(X).
_13074
true.
What is _13074? Is this an address? Is this an ID of some sort? I notice that we'll get a different value each time. Furthermore, why does Prolog report true.? Is this Prolog saying that anything can be unified with X? Why do these appear in the order they do?
If we were to unify X with, say, 1, then the result is different.
?- X = 1, write(X).
1
X = 1.
What is _13074?
The simplest answer is that it represents an uninstantiated variable.
To be more precise from the Prolog Standard
anonymous variable: A variable (represented in a term or Prolog text by _) which differs from every other variable (and anonymous
variable) (see 6.1.2, 6.4.3)
instantiated: A variable is instantiated with respect to substitution if application of the substitution yields an atomic term or a compound term.
A term is instantiated if any of its variables are instantiated.
uninstantiated: A variable is uninstantiated when it is not instantiated.
variable: An object which may be instantiated to a term during execution.
named variable: A variable which is not an anonymous variable (see 6.1.2, 6.4.3)
So obviously all of that is self referential but in short by the standard there are anonymous variables _ and named variables, E.g. X, Y, Ls.
Note that the standard does not say what is the difference between _ and variables with numbers in the suffix, E.g. _13074. Those are implementation specific.
The standard does note for writing a term,
7.10.5 Writing a term
When a term Term is output using write-term/3 (8.14.2) the action which is taken is defined by the rules below:
a) If Term is a variable, a character sequence representing that variable is output. The sequence begins with _ (underscore) and the remaining characters are implementation dependent. The same character sequence is used for each occurrence of a particular variable in Term. A different character sequence is used for each distinct variable in Term.
Since you specifically mention SWI-Prolog there are other variable caveats to be aware of:
named singleton variables AKA auxiliary variables
Named singletons start with a double underscore (__) or a single underscore followed by an uppercase letter, E.g., __var or _Var.
Attribute variables - provide a technique for extending the Prolog unification algorithm Holzbaur, 1992 by hooking the binding of attributed variables. There is no consensus in the Prolog community on the exact definition and interface to attributed variables. The SWI-Prolog interface is identical to the one realised by Bart Demoen for hProlog Demoen, 2002. This interface is simple and available on all Prolog systems that can run the Leuven CHR system (see chapter 9 and the Leuven CHR page).
Global variables - are associations between names (atoms) and terms.
I don't plan to dive deeper into variables as one has to start looking at SWI-Prolog C level source code to really get a more accurate understanding, (ref). I also don't plan to add more from the standard as one would eventually have to reproduce the entire standard here just to cover all of the references.
For more definitions from the Prolog standard see: Is this Prolog terminology correct? (fact, rule, procedure, predicate, ...) The answer is a community wiki so most users can add to it and the OP does not get the points, so upvote all you want.
Is this an address?
No
Sometimes you will also see logic variable used but I don't plan to expand on that here, however for the record SWI-Prolog is NOT based on WAM it is based on A Portable Prolog Compiler.
See above 7.10.5 Writing a term
Is this an ID of some sort?
I would not argue with that in a causal conversation about SWI-Prolog but there is enough problems with that simple analogy to split hairs and start a discussion/debate, E.g. can a blob be assigned to a variable? What is numbervars?
See above 7.10.5 Writing a term
I notice that we'll get a different value each time.
The Prolog standard uses the word occurrence.
See above 7.10.5 Writing a term
why does Prolog report true.?
Prolog is a logic language which executes queries (goal) that result in either true or false or the instantiated values of variables, however there can be side effects such as writing to a file, throwing exceptions, etc.
The Prolog standard states
A.2.1.1 The General Resolution Algorithm
The general resolution of a goal G of a database P is defined by the following non-deterministic algorithm:
a) Start with the initial goal G which is an ordered conjunction of
predications.
b) If G is the singleton true then stop (success).
c) Choose a predication A in G (predication-choice)
d) If A is true, delete it, and proceed to step (b).
e) If no renamed clause in P has a head which unifies with A then stop (failure).
f) Choose a freshly renamed clause in P whose head H unifies with A (clause-choice) where σ = MGU(H, A) and B is the body of the clause,
g) Replace in G the predication A by the body B, flatten and apply the substitution σ.
h) Proceed to step (b).
Also see:
Resolution
MGU
Is this Prolog saying that anything can be unified with X?
For very simple Prolog implementations (ref) then the question would make sense. In the real world and even more so with SWI-Prolog were the rubber meets the road I would have to say not in all cases.
For most Prolog code syntactic unification is what is driving what is happening. See: A.2.1.1 The General Resolution Algorithm above. However if you start to think about things like blobs, attributes, threads, exceptions, and so on then you really have to look at what is a variable, even the kind of variable and what that variable can do , E.g.
?- X is true.
ERROR: Arithmetic: `true/0' is not a function
ERROR: In:
ERROR: [10] _4608 is true
ERROR: [9] toplevel_call(user:user: ...) at c:/program files/swipl/boot/toplevel.pl:1117
?- trie_new(A_trie).
A_trie = <trie>(0000000006E71DB0).
?- write(X).
_13074
true.
Why do these appear in the order they do?
write(X). is the goal entered by the user.
The goal is executed which in this case has the side effect of writing to the current output stream stream, E.g. current_output/1, the variable X which for SWI-Prolog for this occurrence of X is uninstantiated and is displayed as _13074.
The logic query ends and the result of the query being logical is either true or false. Since the query executed successfully the result is true.
If we were to unify X with, say, 1, then the result is different.
?- X = 1, write(X).
1
X = 1.
I will presume you are asking why there is no true at the end.
IIRC with SWI-Prolog, if the query starts with a variable and then the query succeeds with the variable being instantiated that will be reported and no true or false will then appear, E.g.
?- X = 1.
X = 1.
?- current_prolog_flag(double_quotes,V).
V = string.
?- X = 1, Y = 1, X = Y.
X = Y, Y = 1.
If however the query succeeds and no variable was instantiated then the query will report true E.g.
?- 1 = 1.
true.
?- current_prolog_flag(double_quotes,string).
true.
If the the query fails the query will report false E.g.
?- X = 1, Y = 2, X = Y.
false.
?- current_prolog_flag(quotes,String).
false.
I suspect this much information will now have you asking for more details but I won't go much deeper than this as SO is not a place to give a lecture condensed into an answer. I will try to clarify what is written but if it needs a lot more detail expect to be requested to post a new separate question.
I know the info from the standard presented here leaves lots of lose ends. If you really want the details from the standard then purchase the standard as those of us who have have done. I know it is not cheap but for questions like this it is the source of the answers.
Can anyone explain the concept of free variables in Prolog. Is it similar to anonymous variables ? Or is there a difference. Also could be great if an example is given to explain.
tl;dr:
free is a notion to distinguish universally bound (free in clause notation) from existentially bound variables in setof/3, bagof/3, etc. - some people use free to mean "currently not instantiated" and some use it to denote an output argument that's meant to be instantiated by the predicate but that's not how the standard uses it.
long version:
I will quote the Prolog standard on the definition:
7.1.1.4 Free variables set of a term
The free variables set, FVt of a term T with respect to a
term v is a set of variables defined as the set difference
of the variable set (7.1.1.1) of T and BV where BV is a
set of variables defined as the union of the variable set of
v and the existential variables set (7.1.1.3) of T.
where they explicitly note:
The concept of a free variables set is required when defining
bagof/3 (8.10.2) and setof/3 (8.10.3).
Perhaps as a background: in logic, a free variable is one that is not bound by a quantifier (e.g. x is bound and y is free in ∀x p(x,y) ). A (pure) prolog clause head(X) :- goal1(X), goal2(X). can be read as the logical formula ∀X goal1(X) ∧ goal2(X) → head(X). In practice, as long as we use fresh variables whenever we try to unify a goal with a clause, we can just disregard the universal quantifiers. So for our purposes we can treat X in the clause above as free.
This is all and well until meta-predicates come in: say we are interested in the set of first elements in a list of tuples:
?- setof(X, member(X-Y, [1-2, 2-2, 1-3]), Xs).
Y = 2,
Xs = [1, 2] ;
Y = 3,
Xs = [1].
But we get two solutions: the ones where Y=2 and those where Y=3. What I'd actually want to say is: there exists some Y such that X-Y is a member of the list. The Prolog notation for this pattern is to write Var^Term:
?- setof(X, Y^member(X-Y, [1-2, 2-2, 1-3]), Xs).
Xs = [1, 2].
In the first example, both X and Y are free, in the second example X is free and Y is bound.
If we write this as a formula we get setof(X, ∃Y member(X-Y, [1-2, 2-3, 1-3]), Xs) which is not a first order formula anymore (there is an equivalent first order one but this is where the name meta predicate comes in). Now the problem is that the Var^Term notation is purely syntactical - internally there is only one type of variable. But when we describe the behaviour of setof and friends we need to distinguish between free and existentially bound variables. So unless you are using metapredicates, all of your variables can be considered as free (1).
The Learning Prolog link provided by #Reema Q Khan is a bit fuzzy in its use of free. Just looking at the syntax, X is free in X=5, X is 2 + 3. But when we run this query, as soon as we get to the second goal, X has been instantiated to 5 so we are actually running the query 5 is 2 + 3 (2). What is meant in that context is that we expect is/3 to unify its first argument (often called "output" argument). To make sure this always succeeds we would pass a variable here (even though it's perfectly fine not to do it). The text tries to describe this expectation as "free variable" (3).
(1) ok, formally, anything that looks like Var^Term considers Var existentially bound but without meta-predicates this doesn't matter.
(2) I believe there is a clash in notation that some texts use "X is bound to 5" here, which might increase the confusion.
(3) What the should say is that they expect that the argument has not been instantiated yet but even that does not capture the semantics correctly - Paulo Moura already gave the initial ground example 5 is 3 + 2.
Maybe this can help. (If I have prepared it, I might as well post it! Still hard to read, needs simplification.)
In fact, you need to distinguish whether you talk about the syntax of the program or whether you talk about the runtime state of the program.
The word "variable" takes on slightly different meanings in both cases. In common usage, one does not make a distinction, and the understanding this fluent usage provides is good enough. But for beginners, this may be a hurdle.
In logic, the word "variable" has the meaning of "a symbol selected from the set of variable symbols", and it stands for the possibly infinite set of terms it may take on while fulfilling any constraints given by the logical formulae it participates in. This is not the "variable" used in reasoning about an actual programs.
Free Variable:
"is" is a build-in arithmetic evaluator in Prolog. "X is E" requires X to be free variable and E to be arithmetic expression that is possible to evaluate. E can contain variables but these variables has to be bound to numbers, e.g., "X=5, Y is 2*X" is correct Prolog goal.
More Explanation:
http://kti.ms.mff.cuni.cz/~bartak/prolog.old/learning/LearningProlog11.html
Anonymous Variable:
The name of every anonymous variable is _ .
More Explanation:
https://dobrev.com/help/tut/The_anonymous_variable.html#:~:text=The%20anonymous%20variable%20is%20an,of%20_denotes%20a%20distinct%20variable%20.
In Prolog, especially in it's metaprogramming aspects, people often talk about ground and non-ground variables. As well as using predicates such as var/1, nonvar/1 and ground/1. But what exactly is the distincion between them?
My current understanding is the following:
A var is completely uninstantiated (eg. X)
A nonvar is instantiated, but might contain some variables deeper down (eg. term(1,2,Y)). This is similar to a weak head normal form from Haskell.
A ground var is completely instantiated, all the way down (eg. term(1,2,3)).
Is this correct?
Nearly.
If var(X) then variable X designates something that is uninstantiated, a "hole". X is a "fresh variable". Note: That predicate should really be named fresh(...). Whether X is a variable is actually a question about the program text. But what we want to know is whether what is in between the parentheses is a fresh variable (at the moment that call is made, because, quite non-logically, that can change.)
nonvar(X) is just the complement of var(X), same as \+ var(X). Whatever is between the parentheses designates something (if it is a variable) or is something (if it is a non-variable term, as in nonvar(foo)) that is not a "hole".
ground(X) means that whatever is between the parenthese designates something or is something that has no holes in its structure (in effect, no holes at the term's leaves).
Some test code. I expected the compiler to issue more warnings than it did.
:- begin_tests(var_nonvar).
% Amazingly, the compiler does not warn about the code below.
test("var(duh) is always false", fail) :-
var(duh).
% Amazingly, the compiler does not warn about the code below.
test("var(X) is true if X is a fresh variable (X designates a 'hole')") :-
var(_).
% Compiler warning: " Singleton variable, Test is always true: var(X)"
test("var(X) is true if X is a fresh variable (X designates a 'hole')") :-
var(X).
% The hole designated by X is filled with f(_), which has its own hole.
% the result is nonvar (and also nonground)
test("var(X) maybe true but become false as computation progresses") :-
var(X),X=f(_),nonvar(X).
test("var(X) is false otherwise") :-
var(_).
% The hole is designated by an anonymous variable
test("a fresh variable is not ground, it designates a 'hole'", fail) :-
ground(_).
% Both hhe holes are designated by anonymous variables
test("a structure with 'holes' at the leaves is non-ground", fail) :-
ground(f(_,_)).
test("a structure with no 'holes' is ground") :-
ground(f(x,y)).
test("a structure with no 'holes' is ground, take 2") :-
X=f(x,y), ground(X).
% var/1 or ground/1 are questions about the state of computation,
% not about any problem in logic that one models. For example:
test("a structure that is non-ground can be filled as computation progresses") :-
K=f(X,Y), \+ ground(f(X,Y)), X=x, Y=y, ground(f(X,Y)).
:- end_tests(var_nonvar).
Suppose I have a predicate foo/2 which defines a relation between its first and second argument.
What is the most idiomatic and efficient way to change the implementation of foo/2 such that:
if both of its arguments are ground, it acts as before (succeeds if the relation holds, fails otherwise).
if one of the two arguments (or both) are free, it "constrains" those two arguments so that when they will get grounded, the relation will be checked.
In other words, how to correctly implement the behaviour exhibited by dif/2 but with any kind of user-defined relation?
listing(dif/2). was of little help.
Different Prolog implementations provide different features to accomplish this. The mechanism is variously known as coroutining, delayed goals, constraints, and your Prolog system's manual will provide more information.
Here are two variants, which are available in SICStus Prolog and also some other systems.
block/1 directive
In SICStus Prolog (and possibly some other systems), one way to lift a user-defined predicate to such a constrained version is available via the declarative block declaration.
Interestingly, this does not require any changes to the predicate itself!
Suppose you have an impure version of dif/2, using the non-monotonic (\=)/2 predicate:
madif(X, Y) :-
X \= Y.
Then you can turn it into a delayed version for example with:
:- block madif(-, ?),
madif(?, -).
madif(X, Y) :-
X \= Y.
Sample queries and answers:
| ?- madif(a, b).
yes
| ?- madif(a, X).
user:madif(a,X) ? ;
no
| ?- madif(a, X), X = b.
X = b ? ;
no
| ?- madif(X, Y).
user:madif(X,Y) ? ;
no
As required, the evaluation of the goal is delayed until both arguments are instantiated.
when/2
A second way to accomplish this with SICStus Prolog (and other systems that provide this feature) is to use when/2. This requires changes to the predicate itself.
For example, using when/2, you can implement madif/2 like this:
madif(X, Y) :-
when((ground(X),
ground(Y)), X \= Y).
Sample queries and answers:
| ?- madif(X, a).
prolog:trig_ground(X,[],[X],_A,_A),
prolog:when(_A,(ground(X),ground(a)),user:(X\=a)) ? ;
no
| ?- madif(X, a), X = b.
X = b ? ;
no
First and foremostly,
Take the user's viewpoint
... and not that of an implementer. All too often this is ignored – also in existing constraint implementations. And it shows. So here are the most salient aspects to take into account.
Correctness
Obviously this should hold. It is always better to produce clean errors, mostly instantiation errors, better to flounder forever, even better to loop forever than to fail incorrectly. If all else breaks you can wrap your attempt with freeze(_, G_0). Note that you do need a working toplevel to actually see such floundering goals. SICStus has such a toplevel1, in SWI you need to wrap your query as call_residue_vars(Query_0, Vs) to see all attached constraints.
Consistency
Next you want to ensure that your constraint ensures consistency as much as possible. There are many notions of consistency like, domain and bounds consistency. To take your precise requirement think of difgrn/2 and compare it to the built-in dif/2:
difgrn(X, Y) :-
when((ground(X), ground(Y)), X \== Y).
| ?- difgrn(X, X).
prolog:trig_ground(X,[],[X],_A,_B),
prolog:trig_ground(X,[],[X],_A,_C),
prolog:trig_and(_C,[],_A,_B,_A),
prolog:when(_A,(ground(X),ground(X)),user:(X\==X)) ? ;
no
| ?- dif(X, X).
no
| ?- difgrn([], [_]).
prolog:trig_ground(_A,[],[_A],_B,_C),
prolog:trig_and(_C,[],_B,1,_B),
prolog:when(_B,(ground([]),ground([_A])),user:([]\==[_A]))
| ?- dif([], [_]).
yes
One way to implement dif/2 in full strength is to use the very special condition (?=)/2:
difwh(X,Y) :- when(?=(X,Y), X\==Y).
which should answer your question as best as one can:
In other words, how to correctly implement the behaviour exhibited by dif/2 but with any kind of user-defined relation?
But unfortunately, this does not extend to anything else.
The situation becomes even more complex if one considers consistency between various constraints. Think of X in 1..2, dif(X, 1), dif(X, 2).
Answer projections
(For lack of a better word.) Sometimes you want to see your constraints nicely on the toplevel - and the best way is to represent them as goals that themselves will reestablish the exact state required to represent an answer.
See above trig_ground answers, which certainly could be beautified a bit.
Variable projections
Same as answer projections but possible at any point in time, via frozen/2 or copy_term/3.
Subsumption checking
This is useful for diagnostic purposes and loop checks.
For purely syntactic terms, there is subsumes_term/2 which ignores constraints. A prerequisite to perform an effective test is to connect each involved variable to the actual constraint. Consider the goal freeze(X, Y = a) and imagine some subsumption checking with Y as an argument. If Y is no longer attached to the information (as it usually is with current implementations of freeze/2) you will come to the wrong conclusion that this Y subsumes b.
Note as for the actual example of dif/2, this was the very first constraint ever (1972, Prolog 0). A more elaborate description gives Michel van Caneghem in L'anatomie de Prolog, InterÉditions 1986 and Lee Naish in Papers about MU-Prolog.
1 Half-true. For library(clpfd) you need assert(clpfd:full_answer).
I have a predicate that may unify its arguments, for example:
foo(X) :- X = 42.
How can I tell if, while proving foo(X), unification changed X? For example, I would like to know if writeln(X), foo(X), writeln(X) would print the same value for X twice, without actually doing the printing.
My actual implementation of foo/1 is actually much more complex, so please don't suggest specific to the simplified version above. In my program, foo(X) simplifies X using unification, but foo(X) may need to be proven several times until all simplifications have been performed. I would like to be able to write a foohelper(X) predicate that invokes foo(X) until X stops being unified.
Assuming we have only syntactic unification - that is, no constraints:
:- meta_predicate(call_instantiated(0,?)).
call_instantiated(Goal_0, Instantiated) :-
copy_term(Goal_0, Copy_0),
Goal_0,
( subsumes_term(Goal_0, Copy_0) -> % succeeds iff equal u.t.r.
Instantiated = false
; Instantiated = true
).
Note that Goal_0 will or will not be further instantiated. The above subsumes_term/2 tests whether or not Goal_0 is now "more general" than Copy_0. Of course, it cannot be more general, so effectively that test tests whether or not the terms are identical up to renaming of variables.
Compared to using term_variables/2, as #PauloMoura has indicated, this may more may not be more efficient. It primarily depends on the efficiency of subsumes_term/2.
Maybe you can use the standard term_variables/2 predicate? You can call it with your goal before and after calling the goal and check if the returned lists of variables are different. Something like:
...,
term_variables(foo(X), Vars0),
foo(X),
term_variables(foo(X), Vars),
( Vars0 == Vars ->
write(simplified)
; write(not_simplified)
),
...