'Se' em Prolog?
-
27-09-2019 - |
Pergunta
Existe uma maneira de fazer um IF no Prolog, por exemplo, se uma variável for 0, então fazer algumas ações (escreva texto no terminal). Um mais nem sequer é necessário, mas não consigo encontrar nenhuma documentação do IF.
Solução
Um predicado padrão do Prolog fará isso.
isfive(5).
Avaliará como verdadeiro se você ligar com 5 e falhar (retornar false) se você executá -lo com qualquer outra coisa. Para não igual, você usa =
isNotEqual(A,B):- A\=B.
Tecnicamente, não é unificado, mas é semelhante a não ser igual.
Learn Prolog Now é um bom site para aprender o Prolog.
EDIT: Para adicionar outro exemplo.
isEqual(A,A).
Outras dicas
Sim, existe tal construção de controle no ISO Prolog, chamado ->
. Você usa assim:
( condition -> then_clause ; else_clause )
Aqui está um exemplo que usa uma cadeia de mais-cláusulas:
( X < 0 ->
writeln('X is negative. That's weird! Failing now.'),
fail
; X =:= 0 ->
writeln('X is zero.')
; writeln('X is positive.')
)
Observe que, se você omitir a cláusula de outra pessoa, a falha na condição significará que toda a estatura se falhará. Portanto, eu recomendo sempre incluir a cláusula de outra pessoa (mesmo que seja apenas true
).
Prolog prediz 'unificar' -
Então, em um Langauge imperativo, eu escrevia
function bazoo(integer foo)
{
if(foo == 5)
doSomething();
else
doSomeOtherThing();
}
Em Prolog, eu escrevia
bazoo(5) :- doSomething.
bazoo(Foo) :- Foo =/= 5, doSomeOtherThing.
O que, quando você entende os dois estilos, é realmente muito mais claro.
"Eu sou Bazoo para o caso especial quando Foo tem 5"
"Eu sou Bazoo para o caso normal quando Foo não é 5"
Eu achei isso útil para usar um E se declaração em uma regra.
max(X,Y,Z) :-
( X =< Y
-> Z = Y
; Z = X
).
Graças a http://cs.union.edu/~striegnk/learn-prolog-now/html/node89.html
Primeiro, lembre -se de uma lógica clássica de primeira ordem:
"Se P então Q senão R "é equivalente a" (p e Q) ou (non_p e R) ".
Como podemos expressar "se-then-else" como este em Prolog?
Vamos dar o seguinte exemplo concreto:
Se
X
é um membro da lista[1,2]
entãoX
é igual a2
senãoX
é igual a4
.
Podemos corresponder ao padrão acima ("Se P então Q senão R ") se ...
- doença
P
élist_member([1,2],X)
, - condição negada
non_P
énon_member([1,2],X)
, - consequência
Q
éX=2
, e - alternativo
R
éX=4
.
Para expressar a lista (não) de uma maneira pura, definimos:
list_memberd([E|Es],X) :- ( E = X ; dif(E,X), list_memberd(Es,X) ). non_member(Es,X) :- maplist(dif(X),Es).
Vamos verificar diferentes maneiras de expressar "se-then-else" no 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 ; falso. ?- (list_memberd([1,2],X), X=2 ; non_member([1,2],X), X=4), X=2. X = 2 ; falso. ?- 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.
Pontuação de correção 5/5. Pontuação de eficiência 3/5.
(P -> Q ; R)
?- (list_memberd([1,2],X) -> X=2 ; X=4). falso. % 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. falso. % 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. falso. % WRONG
Pontuação de correção 2/5. Pontuação de eficiência 2/5.
(P *-> Q ; R)
?- (list_memberd([1,2],X) *-> X=2 ; X=4). X = 2 ; falso. % WRONG ?- X=2, (list_memberd([1,2],X) *-> X=2 ; X=4), X=2. X = 2 ; falso. ?- (list_memberd([1,2],X) *-> X=2 ; X=4), X=2. X = 2 ; falso. ?- 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. falso. % WRONG
Pontuação de correção 3/5. Pontuação de eficiência 1/5.
(Preliminar) Resumo:
(P,Q ; non_P,R)
está correto, mas precisa de uma implementação discreta denon_P
.(P -> Q ; R)
Perde a semântica declarativa quando a instanciação é insuficiente.(P *-> Q ; R)
é "menos" incompleto do que(P -> Q ; R)
, mas ainda tem problemas semelhantes.
Felizmente para nós, aí são alternativas:Digite a construção de controle logicamente monótono if_/3
!
Podemos usar if_/3
juntamente com o predicado de memória de lista reificada memberd_t/3
igual a:
?- 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 ; falso. ?- 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.
Pontuação de correção 5/5. Pontuação de eficiência 4/5.
A melhor coisa a fazer é usar o chamado cuts
, que tem o símbolo !
.
if_then_else(Condition, Action1, Action2) :- Condition, !, Action1.
if_then_else(Condition, Action1, Action2) :- Action2.
O acima é a estrutura básica de uma função de condição.
Para exemplificar, aqui está o max
função:
max(X,Y,X):-X>Y,!.
max(X,Y,Y):-Y=<X.
Sugiro ler mais documentação sobre cortes, mas em geral eles são como pontos de interrupção. Ex.: Caso o primeiro max
A função retorna um valor verdadeiro, a segunda função não é verificada.
PS: Sou bastante novo no Prolog, mas foi isso que descobri.
Existem essencialmente três maneiras diferentes de como expressar algo como If-Then-Else em Prolog. Para compará -los, considere char_class/2
. Por a
e b
A classe deve ser ab
e other
Para todos os outros termos. Alguém poderia escrever isso desajeitadamente assim:
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 escrever as coisas com mais compactação, é necessária uma construção if-then-else. Prolog tem um embutido:
?- ( ( Ch = a ; Ch = b ) -> Class = ab ; Class = other ).
Ch = a, Class = ab.
Embora essa resposta seja sólida, é incompleta. Apenas a primeira resposta de ( Ch = a ; Ch = b )
é dada. As outras respostas são cortadas. Não é muito relacional, de fato.
Uma construção melhor, geralmente chamada de "corte suave" (não acredite no nome, um corte é um corte é um corte), fornece resultados um pouco melhores (isso está no YAP):
?- ( ( Ch = a ; Ch = b ) *-> Class = ab ; Class = other ).
Ch = a, Class = ab
; Ch = b, Class = ab.
Alternativamente, Sicstus tem if/3
com semântica muito semelhante:
?- if( ( Ch = a ; Ch = b ), Class = ab , Class = other ).
Ch = a, Class = ab
; Ch = b, Class = ab.
Portanto, a última resposta ainda é suprimida. Agora digite library(reif)
por Sicstus, Yap, e Swi. Instale -o e diga:
?- 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).
Observe que todo o if_/3
é compilado para um if-then-else aninhado para
char_class(Ch, Class) :-
if_( ( Ch = a ; Ch = b ), Class = ab , Class = other ).
que se expande no YAP 6.3.4 para:
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
)
).
O programa Prolog na verdade é uma grande condição para "se" com "então", que imprime ", a meta é alcançada" e "else", que imprime ", não foi encontrada sloutions". A, B
significa que "A é verdadeiro e B é verdadeiro", a maioria dos sistemas Prolog não tentará satisfazer "B" se "A" não for alcançado (ou seja, X=3, write('X is 3'),nl
Imprimir 'x é 3' quando x = 3 e não fará nada se x = 2).
( A == B ->
writeln("ok")
;
writeln("nok")
),
A parte else é necessária
Você deve ler Aprenda Prolog agora! Capítulo 10.2 Usando Cut. Isso fornece um exemplo:
max(X,Y,Z) :- X =< Y,!, Y = Z.
a ser dito,
Z
é igual a Y
E SE !
é verdadeiro (o que sempre é) E X
é <= Y
.