2010-11-06 22 views
9

Tiene una curiosidad relacionada con el control de predicado Prolog.Control de predicados en Prolog

Supuestamente tengo un predicado f (A, X) yg (B).

f(A,X):- a,b,c, g(X). 
g(B):- true. 

a - returns true 
b - returns true. 
c - returns false. 
where a,b and c are random predicates. 

¿Cómo puedo seguir evaluando g(X) en el predicado f(A,X) si c devuelve falso?

Respuesta

8

Si su intención es definir f(A,X) tal que g(X) debe evaluar si es o no c falla, entonces:

  1. Usted puede codificar esta usando implicación (->) y/o disyunción (;), o
  2. f(A,X)no necesita ser definido en términos dec. Esto supone que c no tiene efectos secundarios (por ejemplo, afirmando datos de la base de datos usando assert, o imprimiendo IO en una secuencia) que alteran el entorno y que no se pueden deshacer al fallar c, en cuyo caso la primera opción es preferible.

Existen varias alternativas para el uso de la disyunción, tales como:

f(A,X) :- ((a, b, c) ; (a, b)), g(X). 

Esta definición (arriba) no depende de c en absoluto, pero siempre se ejecutará c (siempre y cuando a y b tener éxito). La disyunción (;) permite que PROLOG retroceda para intentar ejecutar a, bnuevamente si c falló y continúa en g(X). Tenga en cuenta que esto es equivalente a:

f(A,X) :- a, b, c, g(X). 
f(A,X) :- a, b, g(X). 

Para que PROLOG no dar marcha atrás para evaluar f(A,X) dos veces debido a la segunda predicado (idénticos) la cabeza f(A,X) para cada evaluación, puede optar por colocar un corte (!), si su implementación lo admite, inmediatamente después de el subgrupo c en la primera cláusula.El corte se coloca después dec porque no queremos que el intérprete se comprometa con esa opción de la cláusula f(A,X) si c ha fallado, en cambio, queremos que el intérprete falle en esta cláusula y pruebe la siguiente, para que efectivamente ignore c y continúe procesando g(X).

También tenga en cuenta que esta solución se basa en a y b que no tiene efectos secundarios, porque cuando falla c, a y b se ejecutan de nuevo. Si todos a efectos secundarios, b, y c tiene, puede intentar usar implicación:

f(A,X) :- a, b, (c -> g(X) ; g(X)). 

Esto también efectivamente siempre ejecutar g(X) si c falla o no, y no se ejecute a y b nuevo si c falla Esta definición de cláusula única tampoco dejará un punto de elección como la sugerencia anterior.

3

Supongo que podría envolver c en ignore/1. Considere, por ejemplo,

?- false, writeln('Hello World!'). 
false. 

?- ignore(false), writeln('Hello World!'). 
Hello World! 
true. 

¿Pero por qué desea continuar si c falla? ¿Cuál es el caso de uso?

Probé este código en SWI-Prolog, no estoy seguro si otros Prologs tienen false/0 y ignore/1. Este último se puede definir como esto sin embargo:

ignore(Goal) :- Goal, !. 
ignore(_). 
+0

+1 para preguntar por qué esto sería útil. El predicado de falla portátil es 'fail', por cierto. (Lo cual es trivial de implementar: 'fail: - 0 = 1.') –

+0

Un escenario donde es posible que desee continuar si' c' falla es cuando 'c' tiene _side-effects_; ver mi respuesta a esta pregunta para más detalles. – sharky