IF-THEN in canonical form? - prolog

defining IF like this :
dynamic(if/1).
op(200, fx, if).
op(150, xfx, then).
op(100, xfy, and).
op(100, xfy, or).
generates the following canonical form :
?- write_canonical(if x then y).
if(then(x,y))
?- write_canonical(if x and z then y).
if(then(and(x,z),y))
?- write_canonical(if x and z or t then y).
if(then(and(x,or(z,t)),y))
Is there a way to generate :
if( conds, then(actions) ).
OR even better :
if( conds, (actions) ).
like this :
if(x,y)
if(x, then(y))
if( and(x,or(z,t)), then(y))
if( and(x,or(z,t)), (y))
one possible alternative I can see :)
?- op(200, xfy, ==>).
?- write_canonical(x ==> y).
==>(x,y)
?- write_canonical(x and z ==> y).
==>(and(x,z),y)

I found better solution to generate normal clauses. Instead of "then" I can just use ":-"
?- write_canonical(if x and z :- y ).
:-(if(and(x,z)),y)
?- assert(if x and z :- write(axz) ).
?- if x and z.
axz

Related

Simulating occurs_check=error in SICStus Prolog

It turns out that SICStus Prolog doesn't have an occurs_check
Prolog flag. At least we couldn't find one, and this here
gives an error message:
/* SICStus 4.6.0 (x86_64-win32-nt-4) */
?- set_prolog_flag(occurs_check, true).
Domain error in argument 1 of set_prolog_flag/2
It seems the value "true" is not so much a problem, the
crictical unifications can be realized via the existing
built-in unify_with_occurs_check/2. An interesting value
of an occurs_check Prolog flag is the value "error".
How would one implement a predicate unify_with_occurs_check_and_error/2 ?
Please note, the solution for unify_with_occurs_check_and_error/2
should behave like unify_with_occurs_check/2, i.e. not trigger
attributed variables.
Here is an example usage of the Prolog flag where present:
?- set_prolog_flag(occurs_check, error).
true.
?- X = f(X).
ERROR: ...
And this is what one would do in SICStus Prolog:
?- unify_with_occurs_check_and_error(X, f(X)).
ERROR: ...
Was adapting the code from here and got the following solution:
unify_with_error(X, Y) :- var(X), var(Y), !, X = Y.
unify_with_error(X, Y) :- var(X), !, must_notin(X, Y), X = Y.
unify_with_error(X, Y) :- var(Y), !, must_notin(Y, X), X = Y.
unify_with_error(X, Y) :- functor(X, F, A), functor(Y, G, B),
F/A = G/B,
X =.. [_|L],
Y =.. [_|R],
maplist(unify_with_error, L, R).
must_notin(X, Y) :-
term_variables(Y, L),
maplist(\==(X), L), !.
must_notin(X, Y) :-
throw(error(occurs_check(X, Y),_)).
Seems to work and no interference with attributed variables:
/* SICStus 4.6.0 (x86_64-win32-nt-4) */
?- unify_with_error(X, f(X)).
error(occurs_check(_413,f(_413)),_409)
?- freeze(X, throw(ball)), unify_with_error(X, f(X)).
error(occurs_check(_413,f(_413)),_409)

Prolog : Evaluating logical expression w/o backtracking with AND/OR op/2?

I'm trying to implement logical expressions evaluation w/o backtracking behavior.
After some experimentation I got it working, here goes :
:- op(80, xfy, and).
:- op(80, xfy, or).
%check/evaluate logical expressions
check(true) :- !.
check(Cond and Conds) :- !, (check(Cond) , check(Conds)).
check(Cond or Conds) :- !, (check(Cond) ; check(Conds)), !. %% <- weird
check(Cond) :- !, call(Cond).
?- check(true and true).
true.
?- check(true and false).
false.
?- check(true or false).
true.
?- check(true or (false and true)).
true.
?- check((true or false) and (false and true)).
false.
?- X = 1 , Y = 2 , check((X = 1) and (Y > 1)).
X = 1,
Y = 2.
So the code works.
My question is why it works, especially the need of two cuts! in the OR expression.
Does this look like a proper Prolog implementation ?
How would you have done it yourself ?

Prolog - Take operation elements

I need a predicate elements(X,L) where X is an operation like neg X, X and Y and returns a list L with all the elements from the operation, like [X,Y].
I already have these:
elements(neg X, [X]).
elements(X and Y, [X,Y]).
elements(X or Y, [X,Y]).
elements(X imp Y, [X,Y]).
But I donĀ“t know how to make it work with complex operations like X imp (Y or Z).
I'm not great at picking operator precedences but here's what I have for your input:
:- op(100, fx, neg).
:- op(200, xfy, and).
:- op(200, xfy, or).
:- op(300, xfy, imp).
elements(Term, Variables) :- term_variables(Term, Variables).
This seems to do what you specified:
?- elements(X imp (Y and Z), Q).
Q = [X, Y, Z].
Is there more to your problem than this?

Function not in prolog

sibling(X, Y):- father(Z, X), father(Z, Y), not (X=Y).
sister(X, Y):- father(Z, X), father(Z, Y), female(X).
brother(X, Y):- father(Z, X), father(Z, Y), male(X).
i'm having a bit problem with using the not function. i've tried not X=Y. but to no avail, the sibling rule still produce error.
if i were to delete the not x=y, the output will be a bit kind of "ugly".
how should i write the not function?
The ISO predicate implementing not provable is called (\+)/1.
However, as #coder explains in the comments, it is much better to use dif/2 to express that two terms are different.
dif/2 is a pure predicate that works correctly in all directions, also if its arguments are not yet instantiated.
For example, with (\+)/1, we get:
?- \+ (X = Y ).
false.
No X and Y exist that satisfy this goal, right? Wrong:
?- X = a, Y = b, \+ (X = Y ).
X = a,
Y = b.
In contrast, with dif/2:
?- dif(X, Y).
dif(X, Y).
and in particular:
?- X = a, Y = b, dif(X, Y).
X = a,
Y = b.
See prolog-dif for more information. dif/2 is with us since the very first Prolog system. I strongly recommend you use it.
SWI Prolog has no notoperator. it can be used as a regular compound term, e.i. not(X).
It must be no space between functor and open parenthesis:
foo( argument list ).
This is the cause of the error.
SWI Prolog suggests ISO-standard replacement for not/1: (\+)/1

Get unique results with Prolog

I have this Prolog code that returns: [[vincent,vincent],[vincent,marcellus],[marcellus,vincent],[marcellus,marcellus],[pumpkin,pumpkin],[honey_bunny,honey_bunny]].
:- initialization main.
loves(vincent, mia).
loves(marcellus, mia).
loves(pumpkin, honey_bunny).
loves(honey_bunny, pumpkin).
jealous(X, Y) :-
loves(X, Z),
loves(Y, Z).
main :-
findall([X, Y], jealous(X, Y), L),
write(L),
halt.
How to get the only results when X != Y?
I tried the following code to get the same results as before.
jealous(X, Y) :-
X \== Y,
loves(X, Z),
loves(Y, Z).
With \=, I got [].
How to get only [vincent,marcellus] as a result?
The order of the goals in your attempted solution is wrong. When called with two distinct variables, the (\==)/2 standard predicate always succeed. The solution is to call the predicate only when its arguments are instantiated:
jealous(X, Y) :-
loves(X, Z),
loves(Y, Z),
X \== Y.
With this fix, your query now returns:
?- findall([X, Y], jealous(X, Y), L).
L = [[vincent, marcellus], [marcellus, vincent]].
So, no one is jealous of himself anymore. But you still get a redundant solution. We can modify the jealous/2 predicate to sort the names in the returned solutions. For example:
jealous(X, Y) :-
loves(X0, Z),
loves(Y0, Z),
X0 \== Y0,
( X0 #< Y0 ->
X = X0, Y = Y0
; X = Y0, Y = X0
).
Now, by using setof/3 instead of findall/3, we get:
?- setof([X, Y], jealous(X, Y), L).
L = [[marcellus, vincent]].
One final observation. A list is a poor solution for representing a pair. The traditional way is to use either X-Y or (X, Y).
Whenever possible, use dif/2 instead of (\==)/2.
dif/2 will help you write logically sound programs.
For details, look at prolog-dif!

Resources