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 resultadosOtra 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