Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Inserting a cut in Prolog to make a relation clause bound but bidirectional

Consider the following Prolog program:

transform([], []).
transform([X | Xs],[Y | Ys]):-
    isSpecial(X),
    isSpecial(Y),
    transformSpecial(X,Y),
    transform(Xs,Ys).
transform([X | Xs],[ X | Ys]):-
    transform(Xs,Ys).

isSpecial(foo).
isSpecial(bar).
isSpecial(foobar).

transformSpecial(X,Y):-
    isSpecial(X),
    isSpecial(Y),
    not(X = Y).

There are cases where I will call tranform([foo, 1, 2], X) and cases where I want to call transform(X, [foo, 1, 2]).

In both cases I want X to unify with [bar, 1, 2] and with [foobar, 1, 2], but not with [foo, 1, 2]. That is, I want that once the predicate correctly recognizes that the second clause is applicable it should stick to only backtrack using the second clause.

Where should I insert the cut to achieve this behavior?

like image 457
Jsevillamol Avatar asked Jan 03 '23 08:01

Jsevillamol


1 Answers

Here is another approach that reuses your existing definition of isSpecial/1. It's biggest drawback is that it makes a lot of assumptions that are not readily visible. So even a small extension might invalidate it. It uses iwhen/2 ("instantiated when").

el_transformed(X, Y) :-
   iwhen(( nonvar(X) ; nonvar(Y) ), iel_transformed(X, Y) ).

iel_transformed(X, Y) :-
   (  nonvar(X)
   -> ( isSpecial(X) -> isSpecial(Y), X \= Y ; X = Y )
   ;  ( isSpecial(Y) -> isSpecial(X), X \= Y ; X = Y )
   ).

Very tricky - I even made a two mistakes on my first try ... and no cut, mince!

For the most general query, we now get an instantiation error. Not very satisfying, but better than an incorrect result.

In general, you would have to look for implementations of constructive negation to handle this in the general case...

like image 179
false Avatar answered May 16 '23 09:05

false