Home     Termíny     Cvičení     Projekty     Rezervace termínu
  1   2   3   4   5   6

6. cvičení

úterý 6.5.2008 a 20.5.2008 8:00 v B311


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ý.

  1. 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).
    
    
  2. 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

    fakt.
    
    hlava :- cíl1, cíl2, ..., cílm.
    
    hlava :- cíl1, cíl2, ..., cílk,!,cílk+2, ..., cíln.
    
    nahradíme postupně pravidly tvaru
    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]).
    
    a upravíme interpret:

    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)]).
    

  3. 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).
    
    


    ^