clause(Head,Body):
``Head'' debe de tener el nombre de una cláusula y nos regresa el
cuerpo de ésta. Los ``hechos'' (i.e., con cuerpo vacío) nos regresa
``true''
?- clause(append(X,Y,Z),L). X = [], Y=_348, Z=_348, L=true; X=[_780|_773], Y=_348, Z=[_780|_775], L=junta(_773,_348,_775)Esto nos permite accesar a cláusulas que tengamos definidas dentro del programa
Asi como podemos accesar predicados con clause/2, también
podemos añadir o quitar clásulas con: assert(X) y
retract(X). e.g.,
?- entiendo. no ?- assert(entiendo). yes ?- entiendo. yes ?- retract(entiendo). yes ?- entiendo. no Otro: a :- b, c. d :- b, not c. e :- c, f. b. c. ?- a. yes ?- assert(f). yes ?- e. yes ?- retract(c). yesCon
assert y retract podemos añadir o quitar reglas
?- retract((append(_,_,_) :- append(_,_,_))). ?- assert((append([H|T],L,[H|R]) :- append(T,L,R))).Variantes:
asserta(X), assertz(X), abolish(F/N)
e.g.,
?- asserta(foo(a,b)), assertz(foo(b,c)), asserta(foo(a,c)). ?- foo(X,Y). ?- functor(Pred,append,3), clause(Pred,Cuerpo), retract((Pred :- Cuerpo)).Una forma en que podemos usar
assert es para guardar
soluciones:
lemma(P) :- P, asserta((P :- !)).
Torres de Hanoi:
hanoi(s(0),A,B,C,[A a B]).
hanoi(s(N),A,B,C,Movs) :-
hanoi(N,A,C,B,Movs1),
hanoi(N,C,B,A,Movs2),
append(Movs1,[A a B |Movs2],Movs).
hanoi(1,A,B,C,[A a B]).
hanoi(N,A,B,C,Movs) :-
N > 1,
N1 is N - 1,
lemma(hanoi(N1,A,C,B,Movs1)),
hanoi(N1,C,B,A,Movs2),
append(Movs1,[A a B |Movs2],Movs).
Para probarlo, primero resolver en general y luego instanciar (para aprovechar los lemmas).
hanoi(N,Discos,Movs) :-
hanoi(N,A,B,C,Movs),
Discos = [A,B,C].
Un ejemplo clásico es Fibonacci: el número N de Fibonacci (excepto
los 2 primeros que es 1) es =
fibo(1,1).
fibo(2,1).
fibo(N,F) :-
N > 2,
N1 is N - 1,
fibo(N1,F1),
N2 is N - 2,
fibo(N2,F2),
F is F1 + F2,
asserta(fibo(N,F)). % Nuevo para guardar resultados
Otra forma de hacerlo es guardar los resultados al ir haciedolo.
Aumentar 2 argumentos mas para tener estos resultados parciales (de N
- 1 y de N -2) Osea: ffibo(2,N,F-1,F-2,(F-1 + F-2))
ffibo(N,F) :- ffibo(2,N,1,1,F).
ffibo(M,N,F1,F2,F2) :- M >= N.
ffibo(M,N,F1,F2,F) :-
M < N,
M1 is M + 1,
NF2 is F1 + F2,
ffibo(M1,N,F2,NF2,F).
Una forma para copiar dos términos es usando assert y
retract
copy(X,Y) :- asserta('$tmp'(X)), retract('$tmp'(Y)).
Un predicado util es:
repeat. repeat :- repeat.
Por ejemplo para consultar ``manualmente'' un archivo:
consulta(Archivo) :-
see(Archivo),
procesa,
seen.
Alternativamente:
consult(Archivo) :-
open(Stream,Archivo,r), % puede ser: r, w, a, rw, ra
procesa(Stream),
close(Stream).
procesa :-
repeat,
read(Clausula), % read(Stream,Clausula),
procesa(Clausula), !.
procesa(X) :-
end_of_file(X), !. % end_of_file(X) :- nonvar(X),
% X = end_of_file.
procesa(Clausula) :-
asserta(Clausula), fail.
Con assert podemos simular variables globales (aunque le quitan
la parte declarativa a los programas, i.e., no usar mucho):
actualiza_var_global(Nombre,Valor) :-
nonvar(Nombre),
retract(var_global(Nombre,_)), !,
asserta(var_global(Nombre,Valor)).
actualiza_var_global(Nombre,Valor) :-
nonvar(Nombre),
asserta(var_global(Nombre,Valor)). % 1a vez
Gensym: crea un nuevo nombre
Antes:
name(Atomo,ListaAscci)
?- name(abc,L).
L = [97,98,99]
gensym(Prefijo,Valor) :- % se guarda: var_global(gensym(foo),4).
var(Valor),
atom(Prefijo),
obten_valor(gensym(Prefijo),N),
N1 is N + 1,
actualiza_var_global(gensym(Prefijo),N1),
concatena(Prefijo,N1,Valor), !.
obten_valor(X,N) :- var_global(X,N), !.
obten_valor(X,0).
concatena(X,Y,XY) :-
name(X,LX),
name(Y,LY),
append(LX,LX,LXY),
name(XY,LXY).
emorales 2012-05-03