190 likes | 462 Vues
Meta-interpreters. Interpreted languages like Prolog can easily treat program code as data can use ‘clause’ to look at program code assert, retract, abolish to create/remove code =.., name, etc to look at terms themselves meta-programming: a program which treats program code as data
E N D
Meta-interpreters COSC 2P93 Prolog: Meta-interpreters • Interpreted languages like Prolog can easily treat program code as data • can use ‘clause’ to look at program code • assert, retract, abolish to create/remove code • =.., name, etc to look at terms themselves • meta-programming: a program which treats program code as data • the program code executed can be a different language than the code the meta-program is written in • or it can be the same language • meta-interpreter: a meta-program that executes a program(“source program”) , possibly written in that language itself • can be used to enhance your language execution • can create prototype languages as well • Prolog is extremely useful for meta-programming
User-defined operators COSC 2P93 Prolog: Meta-interpreters • op(Precedence, Code, Op). • Precedence: numeric code indicating binding strength of operator • smaller number = higher binding • used when parentheses are missing • Code: position and associativity • prefix: fx, fy • postfix: xf, yf • infix: xfx, xfy, yfx, yfy • “x”: argument must have ops of lower precedence • “y”: argument must have ops of equal or lower precedence • Op: characters for operator
User-defined operators COSC 2P93 Prolog: Meta-interpreters Example: ?- op(470, fy, 'not'). % prefix, binds strongest ?- op(475, xfy, 'and'). % infix, binds stronger than ‘or’ ?- op(480, xfy, 'or'). % infix can then write: not a and b or not c --> ((not a) and b) or (not c) regular structure form: or( and( not(a), b ), not(c) )
Meta-interpreter COSC 2P93 Prolog: Meta-interpreters • Example: a meta-interpreter for pure Prolog solve( true ) :- !. solve( not P ) :- !, \+ solve(P). solve( (P, Q) ) :- !, solve(P), solve(Q). solve( P ) :- clause(P, Body), solve(Body). • each clause catches one possible case • ‘true’ is used to represent the termination of a branch of execution • note that clause(P, Body) returns P=parent(mary, bob), B=true for the fact: parent(mary, bob). • the case for (P, Q) breaks up multiple goals; “,” is simply a built-in infix operator • eg. solve((A, B, C, D)) = solve(P, Q) --> P = A, Q = (B, C, D) etc • the cuts are needed so that, during backtracking, true, not P, and (P,Q) won’t be executed by the final case that uses clause
Meta-interpreters COSC 2P93 Prolog: Meta-interpreters • The bulk of the work is done by ‘clause’ • clause actually does the unification of the current goal P with a clause • upon backtracking, clause will backtrack and unify P with the next clause • Note that, when P is unified with the clause Q :- B, the variable substitutions obtained via P=Q are automatically applied to B • The interesting part of meta-interpreters is that you can alter the language behaviour • Example: a meta-interpreter that selects goals from right-to-left solve( true ) :- !. solve( not P ) :- !, \+ solve(P). solve( (P, Q) ) :- !, solve(Q), solve(P). solve( P ) :- clause(P, Body), solve(Body).
Meta-interpreters COSC 2P93 Prolog: Meta-interpreters • Example: A meta-interpreter that doesn’t do any backtracking solve( true ) :- !. solve( not P ) :- !, \+ solve(P). solve( (P, Q) ) :- !, solve(P), solve(Q). solve( P ) :- clause(P, Body), !, solve(Body). • Example: adding some built-in predicates (no longer pure Prolog) solve( true ) :- !. solve( not P ) :- !, \+ solve(P). solve( (P, Q) ) :- !, solve(P), solve(Q). solve( write(X) ) :- !, write(X). solve( read(X) ) :- !, read(X). solve( P ) :- clause(P, Body), solve(Body).
Meta-interpreters COSC 2P93 Prolog: Meta-interpreters • Example: print out a trace of your execution solve( true ) :- !. solve( not(P) ) :- !, \+ solve(P). solve( (P, Q) ) :- !, solve(P), solve(Q). solve( P ) :- (write(‘calling ‘), write(P) ; write(P), write(‘fails’), nl, !, fail), clause(P, Body), write(‘...succeeds’), nl, solve(Body).
Meta-interpreters COSC 2P93 Prolog: Meta-interpreters • By creating new operators, you can even change the syntax of the source program -- great for creating a new language • Example: a new syntax for Prolog ?- op(700, xfy, and). ?- op(800, xfx, if). solve( true ) :- !. solve( not P ) :- !, \+ solve(P). solve( P and Q ) :- !, solve(P), solve(Q). solve( P ) :- P if Body, solve(Body). grandmother(X, Y) if mother(X, Z) and mother(Z, Y). • Note how ‘if’ is just another predicate name: • same as: if(grandmother(X,Y), (mother(X,Z), mother(Z,Y)). • we essentially let the meta-level Prolog do the backtracking for us!
Metainterpreters COSC 2P93 Prolog: Meta-interpreters • Example: a metainterpreter that constructs a logical proof tree solve(true, true) :- !. solve(not P, (not Proof)) :- !, \+ solve(P, Proof). solve((P, Q), (ProofP, ProofQ)) :- !, solve(P, ProofP), solve(Q, ProofQ). solve(P, (P <== ProofP)) :- clause(P, Body), solve(Body, ProofP). • arg 2 contains pattern of proof • Would be nice to print it out in a legible form...
Metainterps COSC 2P93 Prolog: Meta-interpreters prettyprint(E) :- prettyprint2(E, 0). prettyprint2(not A, Indent) :- !, nl, tab(Indent), write('NOT '), prettyprint2(A, Indent). prettyprint2((A,B), Indent) :- !, prettyprint2(A, Indent), nl, tab(Indent), write('AND'), prettyprint2(B, Indent). prettyprint2(A <== true, Indent) :- !, nl, tab(Indent), write(A), write(' <== TRUE').
Prettyprint (cont) COSC 2P93 Prolog: Meta-interpreters prettyprint2(A <== P, Indent) :- !, nl, tab(Indent), write(A), write(' <== '), Indent2 is Indent+3, prettyprint2(P, Indent2). prettyprint2(A, Indent) :- nl, tab(Indent), write(A).
Another metainterpreter: “C” COSC 2P93 Prolog: Meta-interpreters • This example interprets a C-like language. • Grammar of language (Backus-Naur Form, or BNF): E ::= V := A | E;E | if(B, E, E) | while(B, E) A ::= var | const | A+A | A-A | A*A B ::= true | false | A>A | A=A | A>=A • Implement via operators (“:=“, “;”) and structures: if(B, E, F) and while(B, E) • Memory: list of variable/value pairs: • [(a, 0), (flag, 1), (value, 2014), ...]
C metainterpreter: “interp3” COSC 2P93 Prolog: Meta-interpreters • Idea: each statement in language affects the state of memory • To interpret a program, determine how each statement changes memory • This is an “operational semantics” approach. eg. memory before: [(a, 1), (b, 2), (c, 5)] a := b*c memory after: [(a, 10), (b, 2), (c, 5)] eg. E1;E2 where initial memory = Mem1 interpret(E1, Mem1) to generate Mem2 then interpret (E2, Mem2) to generate MemFinal eg. while(B, E): let init memory = Mem1 if B = true then interpret(E, Mem1) to create Mem2 and interpret(while(B, E), Mem2) to create MemF
interp3 code examples COSC 2P93 Prolog: Meta-interpreters ?- op(600, xfy, ':='). interp( (Var := A), Init, Final ) :- interpArith(A, Init, Val), assign(Var, Val, Init, Final). % assign(Var, Val, Before, After): % replaces current (Var, OldVal) pair in with new (Var, Val) pair. assign(Var, Val, MemBefore, MemAfter) :- append(A, [(Var, _)|B], MemBefore), append(A, [(Var,Val)|B], MemAfter), !. assign(Var, _, _, _) :- !, write('Error in assignment: '), write(Var), write(' not found.'), nl, fail.
interp3 COSC 2P93 Prolog: Meta-interpreters interp( (E;F), Init, Final ) :- !, interp(E, Init, Tmp), interp(F, Tmp, Final). interp( if(B, E, F), Init, Final ) :- !, (interpBool(B, Init) -> interp(E, Init, Final) ; interp(F, Init, Final)).
interp3 COSC 2P93 Prolog: Meta-interpreters interp( while(B, E), Init, Final) :- !, (interpBool(B, Init) -> interp(E, Init, Tmp), interp( while(B, E), Tmp, Final) ; Init = Final).
interp3: arithmetic COSC 2P93 Prolog: Meta-interpreters interpArith(A, _, A) :- integer(A), !. interpArith(V, Init, Val) :- member((V,Val), Init), !. interpArith(A+B, Init, Val) :- interpArith(A, Init, ValA), interpArith(B, Init, ValB), Val is ValA + ValB, !. % similar for -, *, ...
interp3: boolean COSC 2P93 Prolog: Meta-interpreters interpBool(true, _) :- !. interpBool(false, _) :- !, fail. interpBool(A > B, Init) :- interpArith(A, Init, ValA), interpArith(B, Init, ValB), !, ValA > ValB.
interp3 COSC 2P93 Prolog: Meta-interpreters ?- test(A,B,C). A = (a:=2;b:=3;a:=4), B = [(a,0),(b,0),(c,0)], C = [(a,4),(b,3),(c,0)] A = (a:=2+1;b:=10-a;if(a>b+a,c:=5,c:= -5)), B = [(a,0),(b,0),(c,0)], C = [(a,3),(b,7),(c,-5)] A = (a:=2;b:=10;c:=1;while(b>0,(c:=c*a;b:=b-1))), B = [(a,0),(b,0),(c,0)], C = [(a,2),(b,0),(c,1024)]