meta-interpreters

19
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 1 COSC 2P93 Prolog: Meta- interpreters

Upload: christopher-moss

Post on 31-Dec-2015

19 views

Category:

Documents


5 download

DESCRIPTION

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 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Meta-interpreters

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

1COSC 2P93 Prolog: Meta-interpreters

Page 2: Meta-interpreters

User-defined operators

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

2COSC 2P93 Prolog: Meta-interpreters

Page 3: Meta-interpreters

User-defined operators

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

3COSC 2P93 Prolog: Meta-interpreters

Page 4: Meta-interpreters

Meta-interpreter

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

4COSC 2P93 Prolog: Meta-interpreters

Page 5: Meta-interpreters

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

5COSC 2P93 Prolog: Meta-interpreters

Page 6: Meta-interpreters

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

6COSC 2P93 Prolog: Meta-interpreters

Page 7: Meta-interpreters

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

7COSC 2P93 Prolog: Meta-interpreters

Page 8: Meta-interpreters

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!

8COSC 2P93 Prolog: Meta-interpreters

Page 9: Meta-interpreters

Metainterpreters

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

9COSC 2P93 Prolog: Meta-interpreters

Page 10: Meta-interpreters

Metainterpsprettyprint(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').

10COSC 2P93 Prolog: Meta-interpreters

Page 11: Meta-interpreters

Prettyprint (cont)

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

11COSC 2P93 Prolog: Meta-interpreters

Page 12: Meta-interpreters

Another metainterpreter: “C”

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

12COSC 2P93 Prolog: Meta-interpreters

Page 13: Meta-interpreters

C metainterpreter: “interp3”

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

13COSC 2P93 Prolog: Meta-interpreters

Page 14: Meta-interpreters

interp3 code examples?- 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.

14COSC 2P93 Prolog: Meta-interpreters

Page 15: Meta-interpreters

interp3

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

15COSC 2P93 Prolog: Meta-interpreters

Page 16: Meta-interpreters

interp3

interp( while(B, E), Init, Final) :-

!,

(interpBool(B, Init) ->

interp(E, Init, Tmp),

interp( while(B, E), Tmp, Final)

;

Init = Final).

16COSC 2P93 Prolog: Meta-interpreters

Page 17: Meta-interpreters

interp3: arithmetic

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 -, *, ...

17COSC 2P93 Prolog: Meta-interpreters

Page 18: Meta-interpreters

interp3: boolean

interpBool(true, _) :- !.

interpBool(false, _) :- !, fail.

interpBool(A > B, Init) :-

interpArith(A, Init, ValA),

interpArith(B, Init, ValB),

!,

ValA > ValB.

18COSC 2P93 Prolog: Meta-interpreters

Page 19: Meta-interpreters

interp3

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

19COSC 2P93 Prolog: Meta-interpreters