online - ''si'' en prolog?
prolog online (10)
Probablemente sea una pregunta estúpida, pero no puedo encontrar ninguna documentación para ello. ¿Hay una manera de hacer un si en prólogo, por ejemplo, si una variable es 0, entonces para hacer algunas acciones (escribir texto en el terminal). Todavía no se necesita un else, pero no puedo encontrar ninguna implementación de if.
¡Deberías leer Learn Prolog ahora! Capítulo 10.2 Uso de Cut . Esto proporciona un ejemplo:
max(X,Y,Z) :- X =< Y,!, Y = Z.
por decir,
Z
es igual a Y
SI !
es verdadero (que siempre es) Y X
es <= Y
Básicamente, existen tres formas diferentes de expresar algo como if-then-else en Prolog. Para compararlos, considere char_class/2
. Para a
y b
la clase debe ser ab
y other
para todos los demás términos. Uno podría escribir esto torpemente así:
char_class(a, ab).
char_class(b, ab).
char_class(X, other) :-
dif(X, a),
dif(X, b).
?- char_class(Ch, Class).
Ch = a, Class = ab
; Ch = b, Class = ab
; Class = other,
dif(Ch, a), dif(Ch, b).
Para escribir cosas de forma más compacta, se necesita una construcción if-then-else. Prolog tiene una incorporada:
?- ( ( Ch = a ; Ch = b ) -> Class = ab ; Class = other ).
Ch = a, Class = ab.
Si bien esta respuesta es sólida, está incompleta. Solo se da la primera respuesta de ( Ch = a ; Ch = b )
. Las otras respuestas son cortadas. No muy relacional, de hecho.
Una mejor construcción, a menudo llamada "corte suave" (no creo que el nombre, un corte es un corte es un corte), da resultados ligeramente mejores (esto es en YAP):
?- ( ( Ch = a ; Ch = b ) *-> Class = ab ; Class = other ).
Ch = a, Class = ab
; Ch = b, Class = ab.
Alternativamente, SICStus tiene if/3
con semántica muy similar:
?- if( ( Ch = a ; Ch = b ), Class = ab , Class = other ).
Ch = a, Class = ab
; Ch = b, Class = ab.
Entonces la última respuesta todavía está suprimida. Ahora ingrese library(reif)
para SICStus , YAP y SWI . Instálalo y di:
?- use_module(library(reif)).
?- if_( ( Ch = a ; Ch = b ), Class = ab , Class = other ).
Ch = a, Class = ab
; Ch = b, Class = ab
; Class = other,
dif(Ch, a), dif(Ch, b).
Tenga en cuenta que todo el if_/3
se compila en un if-then-else salvajemente anidado para
char_class(Ch, Class) :-
if_( ( Ch = a ; Ch = b ), Class = ab , Class = other ).
que se expande en YAP 6.3.4 a:
char_class(A,B) :-
( A/=a
->
( A/=b
->
B=other
;
( A==b
->
B=ab
)
;
A=b,
B=ab
;
dif(A,b),
B=other
)
;
( A==a
->
B=ab
)
;
A=a,
B=ab
;
dif(A,a),
( A/=b
->
B=other
;
( A==b
->
B=ab
)
;
A=b,
B=ab
;
dif(A,b),
B=other
)
).
El programa Prolog en realidad es una condición importante para "si" con "luego" que imprime "Objetivo alcanzado" y "else" que imprime "No se encontraron sloutions". A, B
significa "A es verdadero y B es verdadero", la mayoría de los sistemas de prólogos no intentarán satisfacer "B" si "A" no es alcanzable (es decir, X=3, write(''X is 3''),nl
imprimir ''X es 3'' cuando X = 3, y no hará nada si X = 2).
Encontré esto útil para usar una declaración if en una regla.
max (X, Y, Z): - (X = <Y -> Z = Y; Z = X).
Gracias a http://cs.union.edu/~striegnk/learn-prolog-now/html/node89.html
Lo mejor que puedes hacer es usar los llamados cuts
, ¡que tienen el símbolo !
.
if_then_else(Condition, Action1, Action2) :- Condition, !, Action1.
if_then_else(Condition, Action1, Action2) :- Action2.
Lo anterior es la estructura básica de una función de condición.
Para ejemplificar, aquí está la función max
:
max(X,Y,X):-X>Y,!.
max(X,Y,Y):-Y=<X.
Sugiero leer más documentación sobre cortes, pero en general son como puntos de corte. Ej .: En caso de que la primera función max
devuelva un valor verdadero, la segunda función no se verifica.
PD: Soy bastante nuevo en Prolog, pero esto es lo que descubrí.
Los predicados de Prolog ''unifican'' -
Entonces, en un lenguaje imperativo, escribiría
function bazoo(integer foo)
{
if(foo == 5)
doSomething();
else
doSomeOtherThing();
}
En Prolog escribiría
bazoo(5) :- doSomething.
bazoo(Foo) :- Foo =/= 5, doSomeOtherThing.
que, cuando comprendes ambos estilos, es mucho más claro.
"Soy bazoo para el caso especial cuando foo tiene 5"
"Soy bazoo para el caso normal cuando foo no es 5"
Primero, recordemos alguna lógica clásica de primer orden:
" Si P entonces Q else R" es equivalente a "(P y Q) o (no_P y R)".
¿Cómo podemos expresar "if-then-else" así en Prolog?
Tomemos el siguiente ejemplo concreto:
Si
X
es un miembro de la lista[1,2]
,X
es igual a2
másX
es igual a4
.
Podemos hacer coincidir el patrón anterior (" Si P luego Q else R") si ...
- condición
P
eslist_member([1,2],X)
, - condición negada
non_P
esnon_member([1,2],X)
, - consecuencia
Q
esX=2
, y - la alternativa
R
esX=4
.
Para expresar la membresía de la lista (no) de una manera pura, definimos:
list_memberd([E|Es],X) :- ( E = X ; dif(E,X), list_memberd(Es,X) ). non_member(Es,X) :- maplist(dif(X),Es).
Veamos las diferentes formas de expresar "if-then-else" en Prolog.
(P,Q ; non_P,R)
?- (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4). X = 2 ; X = 4. ?- X=2, (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=2. X = 2 ; false. ?- (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=2. X = 2 ; false. ?- X=4, (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=4. X = 4. ?- (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=4. X = 4.
Puntuación de corrección 5/5. Puntuación de eficiencia 3/5.
(P -> Q ; R)
?- (list_memberd([1,2],X) -> X=2 ; X=4). false. % WRONG ?- X=2, (list_memberd([1,2],X) -> X=2 ; X=4), X=2. X = 2. ?- (list_memberd([1,2],X) -> X=2 ; X=4), X=2. false. % WRONG ?- X=4, (list_memberd([1,2],X) -> X=2 ; X=4), X=4. X = 4. ?- (list_memberd([1,2],X) -> X=2 ; X=4), X=4. false. % WRONG
Puntuación de corrección 2/5. Puntuación de eficiencia 2/5.
(P *-> Q ; R)
?- (list_memberd([1,2],X) *-> X=2 ; X=4). X = 2 ; false. % WRONG ?- X=2, (list_memberd([1,2],X) *-> X=2 ; X=4), X=2. X = 2 ; false. ?- (list_memberd([1,2],X) *-> X=2 ; X=4), X=2. X = 2 ; false. ?- X=4, (list_memberd([1,2],X) *-> X=2 ; X=4), X=4. X = 4. ?- (list_memberd([1,2],X) *-> X=2 ; X=4), X=4. false. % WRONG
Puntuación de corrección 3/5. Puntuación de eficiencia 1/5.
(Preliminar) resumen:
(P,Q ; non_P,R)
es correcto, pero necesita una implementación discreta denon_P
.(P -> Q ; R)
pierde semántica declarativa cuando la instanciación es insuficiente.(P *-> Q ; R)
está "menos" incompleto que(P -> Q ; R)
, pero todavía tiene problemas similares.
Afortunadamente para nosotros, hay alternativas: ingrese la construcción de control lógicamente monótona if_/3
.
Podemos usar if_/3
junto con el predicado de membresía de lista memberd_t/3
así:
?- if_(memberd_t(X,[1,2]), X=2, X=4). X = 2 ; X = 4. ?- X=2, if_(memberd_t(X,[1,2]), X=2, X=4), X=2. X = 2. ?- if_(memberd_t(X,[1,2]), X=2, X=4), X=2. X = 2 ; false. ?- X=4, if_(memberd_t(X,[1,2]), X=2, X=4), X=4. X = 4. ?- if_(memberd_t(X,[1,2]), X=2, X=4), X=4. X = 4.
Puntuación de corrección 5/5. Puntuación de eficiencia 4/5.
Sí, existe una construcción de control en ISO Prolog, llamada ->
. Lo usas así:
( condition -> then_clause ; else_clause )
Aquí hay un ejemplo que usa una cadena de cláusulas else-if:
( X < 0 ->
writeln(''X is negative. That''s weird! Failing now.''),
fail
; X =:= 0 ->
writeln(''X is zero.'')
; writeln(''X is positive.'')
)
Tenga en cuenta que si omite la cláusula else, la condición que falla significará que fallará toda la instrucción if. Por lo tanto, recomiendo siempre incluir la cláusula else (incluso si es true
).
Un predicado de prólogo estándar hará esto.
isfive(5).
evaluará a verdadero si lo llama con 5 y falla (devuelve falso) si lo ejecuta con cualquier otra cosa. Para no igual usas / =
isNotEqual(A,B):- A/=B.
Técnicamente no se unifica, pero es similar a no igual.
Editar: para agregar otro ejemplo.
isEqual(A,A).
( A == B ->
writeln("ok")
;
writeln("nok")
),
La parte else es obligatoria