![]() |
![]() |
Osnova
Metainterprety
Metainterprety (Prologu) jsou interprety, napsané v Prologu, umožňující interpretovat programy v Prologu.
Mějme následující interprety prologovských programů:
Interpret I1
solveI1(Goal):-call(Goal).Interpret I2
solveI2(true):-!. solveI2((A,B)):-!,solveI2(A),solveI2(B). solveI2(X):-predicate_property(X,built_in),!,call(X). solveI2(X):-clause(X,B),solveI2(B).Poznámka:
I2 využívá vestavěné predikáty clause/2, který načítá klauzule z interní programové databáze (konzultované programy), a predicate_property, pomocí kterého umí rozlišit, zda volaný predikát je vestavěný nebo uživatelský.
- Interpretujte pomocí těchto interpretů predikáty member/2 a g/1.
% kvuli pouziti predikatu clause/2 v metainterpretu I2 % musime definovat interpretovane programy jako dynamicke :- dynamic member/2, g/1, g_list/1. member(H, [H|T]). member(H, [_|T]):-member(H,T). g(T):- var(T),!,fail. g(T):- atomic(T),!. g(T):- T=[_|_],!, g_list(T). g(T):- T=..[_|Args], g_list(Args). g_list([]). g_list([H|T]):- g(H), g_list(T).- Zdůvodněte přesně, proč nefunguje interpretace predikátu g/1 interpretem I2.
Interpret I2 ztrácí kontext řezu, neodřízne klauzule interpretovaného programu, ale svoje.
Řešení problému:
všechny uživatelské klauzule
nahradíme postupně pravidly tvarufakt. hlava :- cíl1, cíl2, ..., cílm. hlava :- cíl1, cíl2, ..., cílk,!,cílk+2, ..., cíln.a upravíme interpret:rule(fakt,[],0,[]). rule(hlava,[],0,[cíl1, cíl2, ..., cílm]). rule(hlava,[cíl1, cíl2, ..., cílk],1,[cílk+2, ..., cíln]).Interpret I3
solveI3(X):-predicate_property(X,built_in),!,call(X). solveI3(X):-rule(X,BodyBefore,Cut,BodyAfter),solve_list(BodyBefore), (Cut=1,!;true),solve_list(BodyAfter). solve_list([]). solve_list([A|B]):-solveI3(A),solve_list(B).Můžeme použít programy v následujícím tvaru:rule(member(H, [H|T]),[],0,[]). rule(member(H, [_|T]),[],0,[member(H,T)]). rule(g(T),[var(T)],1,[fail]). rule(g(T),[atomic(T)],1,[]). rule(g(T),[T=[_|_]],1,[g_list(T)]). rule(g(T),[],0,[T=..[_|Args],g_list(Args)]). rule(g_list([]),[],0,[]). rule(g_list([H|T]),[],0,[g(H),g_list(T)]).
- Modifikujte interpret I2 tak, aby místo vestavěné unifikace používal následující unifikaci s testem na výskyt proměnné v unifikovaném termu, tzv. occurs_check (chceme zabránit unifikaci typu X=f(X), s(A,A)=s(B,f(B)) a pod.):
unify(A,B):- (atomic(A);atomic(B)),!,A=B. unify(A,B):- var(A),var(B),!,A=B. unify(A,B):- var(A),!,no_occur(A,B),A=B. unify(A,B):- var(B),!,no_occur(B,A),A=B. unify([H1|T1],[H2|T2]):- !,unify(H1,H2),unify(T1,T2). unify(A,B):- A=..[H1|T1],B=..[H2|T2],H1==H2,unify(T1,T2). no_occur(A,B):-atomic(B),!. no_occur(A,B):-var(B),!,A\==B. no_occur(A,[H|T]):-!,no_occur(A,H),no_occur(A,T). no_occur(A,B):-B=..[_|T],no_occur(A,T).
Řešení:
Vestavěná unifikace se v I2 použije při výběru klauzule (unifikace hlavy klauzule s volaným cílem) a při volání vestavěného predikátu =/2, proto tyto dvě místa předefinujeme (všimněte si umístění řezu, na jiném místě by nefungoval správně).
solve(true):-!. solve((A,B)):-!,solve(A),solve(B). solve(A=B):-!,unify(A,B). solve(X):-predicate_property(X,built_in),!,call(X). solve(X):-functor(X,Fun,Ar),list(Args,Ar),H=..[Fun|Args], clause(H,B),unify(X,H),solve(B). list([],0):-!. list([_|T],N):-N1 is N-1, list(T,N1).
^