rresoudre(LButs, LCl) :- res
oudre
(LButs,
LCl, LCl).
res
oudre
([],
LRef, LCl) :- !.
res
oudre
([B|SButs],
LRef, [[B|Q]|SCl]) :-
/* sans "cut" car on peut
avoir plusieur clauses de même tête*/
append(Q,
SButs, NButs), resprol(NButs, LRef, LRef).
res
oudre
(LButs, LRef,
[_|SCl]) :- resprol(LButs, LRef, SCl).
res
oudre
([B|SButs],
LRef,
[[B|Q]|SCl])
" l'identité entre le premier but B
et la tête de la clause [B|Q]
n'est valable
qu'à l'ordre 0.unif(B, T...)
.Subst
.
Ces substitutions sont soumises à une opération de composition.resoudre
en 3 clauses demeure inchangé :resoudre([], Ref, LCl, Subst) :- !. /*resoudre(LButs,
LRef,
LCl, Subst) */
resoudre([B|SB], LRef, [[T|Q]|LCl], Subst) :-
alpha_conv([T|Q], [NT|NQ]), unif(B, NT,
Sb),
appsub(Sb, SB, NSB), appsub(Sb, NQ,
SNQ), append(SNQ, NSB, NB),
resoudre(NB, LRef, LRef, Ssb),
compose(Sb, Ssb, Subst).
resoudre(LB, LRef, [_|LCl], Subst) :- resoudre(LB, LRef, LCl, Subst).
p(A,
f(g(B)), f(A))
p(h(B,
C), f(C), f(h(U, V)))
A
, B
, C
, U
et V
sont des variables (à valeurs d'individus), et f
, g
,
h
et p
des constantes (désignant des fonctions) A = h(U,g(U)) ; B = U ; C = g(U) ; U = U ; V
= g(U)
] p(h(U,g(U)), f(g(U)), f(h(U,g(U))))
A = h(k(Z),g(k(Z))) ; B =
k(Z);
C =
g(k(Z)) ; U = k(Z) ; V = g(k(Z)
] U
par le
terme k(Z)
.f(x)
et t2 = 1
a une infinité de solutions incomparables =
" t1 = t2
"
dénote l'unifiabilité des termes t1
et t2
,
non leur égalité verbatim.X = toto.
" réussit, avec justement X
valant toto
.\=
" : "t1
\= t2
" équivaut à "not(t1
= t2)
"==
"X == toto.
" échoue,f(X) == f(Y).
", mais "f(X)
== f(X).
" réussit.\==
" : "t1
\== t2
" équivaut à "not(t1
== t2)
"=@=
"Term1
is
`structurally equal' to Term2
. ==/2
),
but stronger than unification (=/2
). Two terms
are structurally equal if their tree representation is identical and
they have the same `pattern' of variables. a
=@= A false
A =@=
B true
x(A,A) =@=
x(B,C) false
x(A,A) =@=
x(B,B) true
x(A,B) =@=
x(C,D) true
\=@=
" : "t1
\
=@=
t2
"
équivaut à "not(t1 =@= t2)
"=:=
"Expr1 =:= Expr2
: True
if expression Expr1 evaluates to a number equal to Expr2.is/2
should be used with unbound left operand. If equality is to be tested, =:=/2
should be used. ?- 1 is sin(pi/2).
Fails!. sin(pi/2) evaluates to the float 1.0, which does not unify with
the integer 1.?- 1 =:= sin(pi/2).
Succeeds as expected.=\=
" : "t1
=\=
t2
"
True if expression t1
evaluates to a number non-equal to t2
.X = f(X)
est f(f(f(...( ))))
.?- X = f(X).
X = f(**).
unify_with_occurs_check
.?- unify_with_occurs_check(X, f(X)).
false.
isvar
" var
" est un prédicat réservé de Prolog
).:- dynamic isvar/1. % sera modifié plus tard pour
alpha-conversion
isvar(a). isvar(b). isvar(c). isvar(d).
isvar(u). isvar(v).
isvar(x). isvar(y). isvar(z).
rob1( p(a, f(g(b)), f(a)) ).
rob2( p(h(b, c), f(c), f(h(u, v))) ).
jg1( p(g(z), y) ).
jg2( p(x, f(u)) ).
jgg1( p(a, x, f(g(y))) ).
jgg2( p(z, f(x), f(u)) ). /* avec occur-check */
nocc(Var, Terme)
et son itéré dans une
liste de termes : locc(Var, LTermes)
nocc(Var, Var) :- !, fail.
nocc(Var, Atom) :- atomic(Atom),!.
nocc(Var, Terme) :- Terme =..[Fonc|LArgs], locc(Var, LArgs).
locc(Var, []).
locc(Var, [A|S]) :- nocc(Var, A), locc(Var, S).
a
dans [[a,
f(b)], [b, g(c)], [c, x]]
est f(g(x))
et
non pas f(b)
.aval(Atome, Subst, Val) :-
isvar(Atome), present(Atome, Subst, Val1),!,
appsub(Subst, Val1, Val).
aval(Atome, Subst, Atome).
present(Var, Env, Val) :- member([Var, Val], Env).
appsub(Subst,
Terme, Res)
lappsub(Subst,
LTermes, LRes)
appsub(Subst, Terme, Val) :-
atomic(Terme),!, aval(Terme, Subst, Val).
appsub(Subst, Terme, Val) :- Terme=..[Fonc|LArgs],
lappsub(Subst, LArgs, LVals),
Val =..
[Fonc|LVals].
lappsub(Subst, [], []).
lappsub(Subst, [A|S], [V|LV]) :- appsub(Subst, A, V),
lappsub(Subst, S, LV).
unif(Terme1,
Terme2, Subst)
lunif(L1, L2, Subst)
unif(Terme1, Terme2, []) :- Terme1 = Terme2,!.
unif(Terme1, Terme2, [[Terme1, Terme2]]) :- isvar(Terme1),!,
nocc(Terme1, Terme2).
unif(Terme1, Terme2, [[Terme2, Terme1]]) :- isvar(Terme2),!,
nocc(Terme2, Terme1).
unif(Terme1, Terme2, Subst) :- Terme1 =.. [Fonc|LArgs1],
Terme2
=.. [Fonc|LArgs2],
lunif(LArgs1, LArgs2, Subst).
lunif([], [], []).
lunif([A1|S1], [A2|S2], Subst) :-
unif(A1, A2, Sub),
lappsub(Sub, S1, L1),
lappsub(Sub, S2, L2),
lunif(L1, L2, LSub),
append(Sub, LSub,Subst).
| ?- rob1(X), rob2(Y), unif(X,Y, S),
| appsub(S,X,
NX), appsub(S, Y, NY),
NX=NY.
X = p(a,f(g(b)),f(a))
Y = p(h(b,c),f(c),f(h(u,v)))
S = [[a,h(b,c)],[c,g(b)],[b,u],[v,g(u)]]
NX = p(h(u,g(u)),f(g(u)),f(h(u,g(u))))
NY = p(h(u,g(u)),f(g(u)),f(h(u,g(u))))
| ?-
bin(4, 2)
par le triangle de
Pascal ?L'arbre du calcul
|
En Prolog c'est beaucoup plus compliqué ! ?- trace, bin(4, 2, R). chaque résolution d'un but engendre une interrogation, à laquelle on peut répondre de différentes façons. La réponse de base, par retour-chariot, fait avancer d'un pas (le verbe anglais to creep est intraduisible en français)... ^ Call: (10) _L192 is 3-1 ? creep On y lit néanmoins l'arbre du calcul récursif... Les variables qui apparaissent ont toutes des noms nouveaux produits par l'α-conversion. |
call
, exit
(avec succès), redo
et fail
creep
) ? leap
) ? abort
) ? exit
) ?help
, h
ou ?
).?- trace, pere(cesar, X).
Call: (8) pere(cesar, _G204) ? creep
Exit: (8) pere(cesar, adrienne) ? creep
X = adrienne ;
Redo: (8) pere(cesar, _G204) ? creep
Exit: (8) pere(cesar, marc) ? creep
X = marc.
:- dynamic generation/1.
generation(0).
new-generation(N) :- generation(A), N is A+1,
retract(generation(A)),
assert(generation(N)).
new-name(A, N, NA) :- name(A, LA), name(N, LN), append(LA, LN, LNA),
name(NA, LNA), assert(isvar(NA)).
renove-terme(A, N, NA) :- isvar(A), !, new-name(A, N,
NA).
renove-terme(A, N, A) :- atomic(A), !.
renove-terme(T, N, NT) :- T =..[Fonc|LArgs],
renove-ltermes(LArgs, N,
LNArgs),
NT =.. [Fonc|LNArgs].
renove-ltermes([], N, []).
renove-ltermes([T|LT], N, [NT|NLT]) :- renove-terme(T, N, NT),
renove-ltermes(LT, N, NLT).
alpha_conv([T|Q], [NT|NQ]) :- new-generation(N),
renove-terme(T, N, NT),
renove-ltermes(Q, N, NQ).
prolog(LButs, LRef) :- resoudre(LButs, LRef, LRef, Subst),
liste-var(LButs, LVar), sort(LVar,
SLVar),
lappsub(Subst, SLVar, SLVal),
display(SLVar, SLVal).
liste-var(Terme, [Terme]) :- isvar(Terme), !. /* sans duplication */
liste-var(Terme, []) :- atomic(Terme), !.
liste-var(Terme, LV) :- Terme=..[Fonc|LArgs], lliste-var(LArgs, LV).
lliste-var([], []).
lliste-var([T|S], LV) :- liste-var(T, LT), lliste-var(S, LS),
add(LT, LS, LV). /* evite les
duplications */
add([], X, X).
add([A|S], X, Y) :- present(A, X), !, add(S, X, Y).
add([A|S], X, [A|Y]) :- add(S, X, Y).
present(A, [B|S]):- A=B, !.
present(A, [_|S]):- present(A, S).
display([], []) :- write('OK !'), nl. /* pour voir les jeux de valeurs
*/
display([Var|SVar], [Val|SVal]) :- write(Var), write(' = '), write(Val),
nl, display(SVar, SVal).
/* Exemples de programmes pour Quasi-Prolog */
base1([
[pere(jules, cesar)], [mere(silvia,
cesar)],
[pere(cesar,adrienne)],
[mere(lea,adrienne)],
[pere(cesar,marc)], [mere(lea,marc)],
[pere(marc, antoine)], [mere(enza,
antoine)],
[pere(marc, paul)], [mere(enza, paul)],
[parents(x,y,z), pere(x,z), mere(y,z)],
[gdparents(x,y,z), pere(u,z),
parents(x,y,u)],
[gdparents(x,y,z), mere(u,z),
parents(x,y,u)],
[gdpere(x, y), pere(x, z), pere(z, y)],
[gdmere(x, y), mere(x, z), pere(z, y)],
[gdmere(x, y), mere(x, z), mere(z, y)],
[gdpere(x, y), pere(x, z), pere(z, y)],
[ancetre(x,x)],
[ancetre(x,y), pere(x,z), ancetre(z,y)],
[ancetre(x,y), mere(x,z), ancetre(z,y)]
]).
base2([
[entier(o)], [entier(succ(x)),
entier(x)],
[add(o, x, x)], [add(x, o, x)],
[add(succ(a), succ(b), succ(succ(x))),
add(a,b,x)]
]).
/* Les predicats d'appel */
plg1(B) :- base1(R), prolog(B, R), fail.
plg2(B) :- base2(R), prolog(B, R), fail.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| ?- plg1([pere(cesar, x), mere(lea, x)]).
x = adrienne
OK !
x = marc
OK !
false
| ?- plg1([ancetre(x, paul), mere(x, y)]).
x = silvia
y = cesar
OK !
x = lea
y = adrienne
OK !
x = lea
y = marc
OK !
x = enza
y = antoine
OK !
x = enza
y = paul
OK !
false
| ?- plg2([entier(succ(succ(succ(o))))]).
OK !
false
| ?- plg2([entier(suc(0))]).
false
| ?- plg2([add(x, y, succ(succ(o)))]).
x = o
y = succ(succ(o))
OK !
x = succ(succ(o))
y = o
OK !
x = succ(o)
y = succ(o)
OK !
x = succ(o)
y = succ(o)
OK !
false
| ?-