dif with occurs check - prolog

Is there a dif with occurs check?
This here works:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.7)
?- set_prolog_flag(occurs_check, true).
true.
?- dif(X,f(Y)), X = Y.
X = Y.
But the above is not feasible, since occurs check
is a global flag, I get the following:
SWI-Prolog console for thread 3
?- X=f(X).
false.

Now, Scryer supports dif/2 with occurs-check when the corresponding flag is set:
?- use_module(library(dif)).
true.
?- set_prolog_flag(occurs_check, true).
true.
?- dif(-X,X).
true.
?- dif(-X,Y).
dif:dif(- X,Y).
?- dif(-X,X), X = a.
X = a.

In my system, I made a new predicate dif_with_occurs_check/2. As the name says, it is dif/2 with occurs check, so no need to set a flag. But there is an additional benefit, dif/2 is optimized to listen to fewer variables:
/* listens only to changes in X */
?- dif(X, f(Y)).
/* listens to changes in X and Y */
?- dif_with_occurs_check(X, f(Y)).
This is necessary, so that we can wake up dif_with_occurs_check/2 when change the variable Y for example to Y = X. dif_with_occurs_check/2 will then remove its own constraint X = f(Y) which has become X = f(X) and therefore obsolete.
?- dif(X,f(Y)), X = Y.
X = Y,
dif(Y, f(Y))
?- dif_with_occurs_check(X,f(Y)), X = Y.
X = Y
Open Source: Module "herbrand"
https://github.com/jburse/jekejeke-devel/blob/master/jekmin/headless/jekmin/reference/term/herbrand.p

Related

How bootstrap setarg_with_occurs_check/3 in Prolog?

How would one go about and bootstrap setarg_with_occurs_check/3 in
Prolog. It seems Prolog has two ways to create cyclic data structures.
Not only unification can do that, but also setarg/3:
/* SWI-Prolog 8.3.26 */
?- X = f(X).
X = f(X).
?- X = f(0), setarg(1,X,X).
X = f(X).
Lets say I want the analogue of unify_with_occurs_check/2 for
setarg/3. How would one go about and implement the same?
(BTW In some Prolog systems setarg/3 sometimes goes by the
name change_arg/3, and some even don't have it at all)
I think you can use the ISO predicate acyclic_term/1. Thus, in SWI-Prolog, you can define:
setarg_with_occurs_check(Arg, Term, Value) :-
setarg(Arg, Term, Value),
acyclic_term(Term).
Examples:
?- X = f(0), setarg_with_occurs_check(1,X,Y).
X = f(Y).
?- X = f(0), setarg_with_occurs_check(1,X,X).
false.
?- X = f(X), Y = g(Z), setarg_with_occurs_check(1,Y,X).
false.

Boolean unification in Prolog?

I am struggling alreay for a long time with the
following problem. I want to make the usual unification
of Prolog more smart.
Basically I want that certain variables understand that
for example 0 = ~1 and 1 = ~0. This doesn't work normally:
?- op(300, fy, ~).
true.
?- X = ~Y, Y = 0.
X = ~0,
Y = 0.
I know that that CLP(B) can do it:
Welcome to SWI-Prolog (threaded, 64 bits, version 8.3.7)
:- use_module(library(clpb)).
true.
?- sat(X=:= ~Y), Y = 0.
X = 1,
Y = 0.
But I require something more lightweight than loading a full CLP(B) library. Any ideas?
It seems that SWI-Prologs when/2 does the job. I am using
the Quine algorithm from here to partially evaluate a boolean expression.
I can then define a Boolean let/2 predicate:
let(X, Y) :-
eval(Y, H),
term_variables(H, L),
( L== [] -> X = H;
cond(L, R),
when(R, let(X, H))).
cond([X], nonvar(X)) :- !.
cond([X,Y|Z], (nonvar(X);T)) :-
cond([Y|Z], T).
The above predicate will reevaluate the expression assigned
to the variable X when ever some variable inside the expression
changes. The expression is associate with the variable X through when/2. Since we see when/2 in the top-level, we see the associated expression:
?- let(X, ~Y).
when(nonvar(Y), let(X, ~Y))
?- let(X, Y+Z).
when((nonvar(Y); nonvar(Z)), let(X, Y+Z))
And we can also do our use case and even more:
?- let(X, ~Y), Y = 0.
X = 1,
Y = 0.
?- let(X, Y+Z), Y = 0.
Y = 0,
when(nonvar(Z), let(X, Z))
?- let(X, Y+Z), Y = 0, Z = 1.
X = 1,
Y = 0,
Z = 1

Prolog only check variable is instantiated

In Prolog, is it possible to check if the variable is certain value only if the variable is instantiated.
? - my_rule(X).
my_rule(X):-
X = 4,
write('continue').
Here I am trying to check if the X is 4, if the X is 4 then we continue, but I also want the rule to continue if the X is _, but when it is called with something else, like X is 3 then it should not continue.
So the results would look like this:
?- my_rule(X).
continue
true.
?- my_rule(4).
continue
true.
?- my_rule(3).
false.
Have a look at var/1, atom/1 and ground/1:
var(X) is true if and only if X is a variable.
?- var(X), X= 1.
X = 1.
?- X=1, var(X).
false.
?- X=f(Y), var(X).
false.
atom(X) is true if X is an atom.
?- atom(a).
true.
?- atom(f(a)).
false.
?- atom(X).
false.
ground(X) is true if X is ground (does not contain variables).
?- ground(f(a)).
true.
?- ground(f(X)).
false.
The three predicates are deterministic (i.e. do not backtrack) and you can safely negate them.
Your code become something like this:
my_rule(4) :-
% handle the 4 case
my_rule(X) :-
var(X),
% general case
I'm just not sure if this is, what you want. In most programs, there should be no necessity to handle the variable only case separately. Also be aware that such meta-logical tests are outside the scope of classical logic. If compare the queries X = 1, var(X) and var(X), X = 1, you can see that the conjunction is not commutative anymore but in logic A ∧ B = B ∧ A holds.
You can use double negation ( \+(\+(...)) ):
In your example:
my_rule(X):-
\+(\+(X = 4)),
write('continue').
my_rule(X):-
check(X),
write('continue').
% A fact used to check a value.
check(4).
% A predicate that checks if X is unbound, e.g. a variable.
check(X) :-
var(X).
Verification of desired results.
?- my_rule(X).
continue
X = 4 ;
continue
true.
?- my_rule(4).
continue
true ;
false.
?- my_rule(3).
false.

Prolog ... define predicate that checks if both arguments are/point to the same atom

I have a prolog predicate that takes two parameters (both labelled X here since they should be the same) and compares them to see if they evaluate to the same atom. That is the intent. However, the predicate unexpectedly returns false when both arguments are variables.
I'm trying to define a notion of an expression in sentential logic / propositional calculus being in "implication normal form" in Prolog. Implication normal form here meaning that all connectives are replaced with -> and falsum.
As a base case, I want to say that an expression consisting entirely of an atom is already in normal form with itself.
Here's how I'm attempting to express that. I'm repeating a parameter name instead of doing some type of check of sameness between the parameters.
% foo.P
implication_normal(X, X) :- atom(X).
This incomplete-but-still-useful definition is intended to capture the fact that implication_normal(x, x) is true but implication_normal(x, y) is false.
In some ways it seems to work:
$ swipl -s foo.P
?- implication_normal(x, x).
true.
?- implication_normal(x, y).
false.
?- implication_normal(1, 1).
false.
It does the wrong thing with variables (It should be enumerating pairs of "binding contexts" where X and Z happen to point to the same atom).
?- implication_normal(X, Z).
false.
It also just returns false if you give it the same variable twice.
?- implication_normal(X, X).
false.
for some strange reason, the behavior is correct if you give it a variable and a single atom (and you get failure with an integer).
?- implication_normal(X, z).
X = z.
?- implication_normal(X, 1).
false.
and similarly if the variable is second.
?- implication_normal(z, X).
X = z.
?- implication_normal(1, X).
false.
How do I change the definition of implication_normal so that it enumerates in all the cases where variables are supplied?
The standard atom/1 predicate is a type-checking predicate. It doesn't enumerate atoms. It just deterministically checks if its argument is an atom. Moreover, your definition of the implication_normal /2 predicate attempts to unify its two arguments and, if the unification is successful, calls atom/1 with the resulting term. That's why a call such as implication_normal(X, z) succeeds: X is unified with z and atom(z) is true.
Note that some Prolog systems provide a current_atom/1 that does enumerate atoms. On those systems, you could write instead:
implication_normal(X, X) :- current_atom(X).
Some sample calls using SWI-Prolog:
?- implication_normal(X, Z).
X = Z, Z = '' ;
X = Z, Z = abort ;
X = Z, Z = '$aborted'
...
?- implication_normal(X, X).
X = '' ;
X = abort ;
X = '$aborted' ;
...
?- implication_normal(X, z).
X = z.
?- implication_normal(X, 1).
false.

Prolog: comparing predicate value with constant

I have some problems with prolog, specifically I can't compare a value of a predicate with a constant.
predicate(9).
compare(X,Y) :- X<Y.
Running the program:
?-compare(predicate(X),10).
Why doesn't it work? Thank you for your answers.
Predicates don't return values in the way that a function does.
This is C:
int nine() { return 9; }
int main() {
int x = nine(); /* x is now 9 */
}
This is Prolog:
% source
nine(9).
% from the top level
?- nine(X).
X = 9.
?- nine(X), X < 10.
X = 9.
?- nine(X), compare(C1, X, 10), compare(C2, 10, X).
X = 9,
C1 = (<),
C2 = (>).
Few things (trying not to use too much Prolog lingo):
What your predicate/1 and my nine/1 does is to unify its only argument with the integer 9. If the unification succeeds, the predicate succeeds, and now the argument is bound to 9. If the unification fails, the predicate fails.
?- nine(9).
true.
?- nine(nine).
false.
?- nine(X), nine(Y).
X = Y, Y = 9.
You will also notice that there is a standard predicate compare/3 that can be used for comparison of Prolog terms. Because predicates don't have a return value in the way that functions do, it uses an extra argument to report the result of the comparison. You could have instead tried something along the lines of:
% greater_than(X, Y) : true if X is greater than Y according
% to the standard order of terms
greater_than(X, Y) :- X #> Y.
But this is just defining an alias for #>/2, which is a predicate itself (but has been declared as an operator so that you can use it in infix notation).
?- #>(a, b).
false.
?- #>(b, a).
true.
Same goes for </2, which is a predicate for comparison of arithmetic expressions:
?- 2 + 4 =< 6.
true.
?- nine(X), X > 10 - X.
X = 9.
?- nine(X), X > 10.
false.
Like #Boris said before "Predicates don't return values in the way that a function does." Here you must try to instantiate the variables in the head of your rule.
If you are trying with you predicate compare/2 to find a number X greater than Y, and at the same time this number X should be a fact predicate/1, then add both conditions to the body of your rule or predicate compare/2
predicate(9).
compare(X,Y) :- predicate(X), X<Y.
Now if you consult:
?- compare(X,10).
The answer will be
X = 9
As you can see, 9 is smaller than 10, and at the same time 9 is a fact predicate/1. And that is the return value you are looking for.
Caution
Note that the operator >/2, requires that both sides are instantiated, so in this case you won't be able ask for the value Y in your predicate
?- compare(9, Y)
</2: Arguments are not sufficiently instantiated
Maybe and if it make sense, you can try to instantiate this variable to a fact predicate/1 too.
predicate(9).
predicate(10).
compare(X,Y) :- predicate(X), predicate(Y), X<Y.
?- compare(9,Y).
Y = 10

Resources