Negación por falla

En particular el ! se puede usar en conjunción con fail para indicar que si ya llegaste ahi entonces falla, i.e., !, fail. E.g.,

impuesto(X,N) :- desempleado(X), !, fail.
impuesto(X,N) :- sueldo(X,Sx), Sx < 4*Min, !, fail.
impuesto(X,N) :- ...

Por ejemplo para indicar a menos que:

gusta(Maria,X) :- vibora(X), !, fail.
gusta(Maria,X) :- animal(X).

gusta(Maria,X) :-
      ( vibora(X), !, fail
      ; animal(X) ).

Usando la misma idea:

diferente(X,X) :- !, fail.
diferente(X,Y).

diferente(X,Y) :-
     ( X = Y, !, fail
     ; true ).

not: aunque los Prologs tienen definido NOT, lo podemos definir en términos de ! y fail

not(P) :- P, !, fail.
not(P).
Aqui si cambiamos el orden cambia el sentido!!

Generalmente not se define como \+

gusta(maria,X) :- animal(X), \+ vibora(X).

diferente(X,Y) :- \+ X = Y.

Cuando se usa \+ el orden de las reglas es escencial. Lo que hace Prolog es Negación por Falla con CWA (i.e., si no lo puede probar, entonces asume que es falso)

NO es negación lógica y puede tener problemas:

est_soltero(X) :-
       \+ casado(X),
       estudiante(X).
estudiante(juan).
casado(pepe).

?- est_soltero(X)
Asi falla sin considerar a juan, sin embargo, si cambiamos el orden de las literales en la regla, si se cumple. Otros casos que ilustran esto:
?- \+ X = 1, X = 2

r(a).
q(b).
p(X) :- \+ r(X).

?- q(X), p(X).
X = b.

?- p(X), q(X).
no

p(s(X)) :- p(X).
q(a).
?- \+ (p(X), q(X)).
Sin embargo, podemos usarlo en ciertos casos:
gusta(X,Y) :- animal(X), \+ vibora(X).

conj_disj(C1,C2) :-
     \+ (member(X,C1), member(X,C2)).

Los CUTs se pueden clasificar en:

p :- a,b. $\Longrightarrow (a \wedge b) \vee c$
p :- c.

p :- a,!,b. $\Longrightarrow (a \wedge b) \vee (\neg a
\wedge c)$
p :- c.

p :- c. $\Longrightarrow c \vee (a \wedge b) $
p :- a,!,b.
e.g., (de nuevo recordar la definición de MAX)

Los CUTs rojos eliminan pruebas y a veces son necesarios, pero hay que tener mucho cuidado porque esto afecta el sentido del programa. Un ejemplo útil, es definiendo If-Then-Else

ifthenelse(P,Q,R) :- P, !, Q.
ifthenelse(P,Q,R) :- R.
Ponerlo ``bien'' sería añadir en la segunda regla: \+ not P, R, pero evaluar \+ P puede ser MUY costoso, y de hecho ya lo hicimos una vez (si no, no estaríamos en la segunda regla)

ifthenelse: viene definido en la mayoría de los Prologs como: P -> Q ; R

Notas (sobre los CUTs):

Usos de CUTs rojos: (i) obtener la primera solución (ii) obtener un efecto if-then-else. E.g.,

primera(Meta) :- call(Meta), !.

Otro ejemplo:

aplana(L,LA) :- aplana(L,[],LA).

aplana([],L,L) :- !.
aplana([H|T],L1,L) :-
      !,
      aplana(H,L1,L2),
      aplana(T,L2,L).
aplana(X,L,[X|L]).
Aqui los CUTs de las dos primeras cláusulas, son para darle sentido a la última!!. Deberíamos de tener en lugar de los CUTs, en la última:
X \= [], X \= [_|_].

e.g.,:

?- aplana([],X).
X = []
?- X = [_], aplana([],X).
X = [[]]
Que pasó?? El ! debe ponerse tan pronto que se determine que el camino de prueba es el correcto: i.e., aplana([],L1,L) :- !, L1 = L

emorales 2012-05-03