1 / 25

Meta-Programming through Typeful Code Representation

Meta-Programming through Typeful Code Representation. Chiyan Chen and Hongwei Xi Boston University. Talk Overview. Meta-Programming Examples Untyped (Scheme) Typed (MetaML) Some Issues on Typing Meta-Programs Typeful Code Representation Higher-Order Abstract Syntax

lara
Download Presentation

Meta-Programming through Typeful Code Representation

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Meta-Programming throughTypeful Code Representation Chiyan Chen and Hongwei Xi Boston University

  2. Talk Overview • Meta-Programming Examples • Untyped (Scheme) • Typed (MetaML) • Some Issues on Typing Meta-Programs • Typeful Code Representation • Higher-Order Abstract Syntax • First-Order Abstract Syntax (via de Bruijn indexes) • A Translation to Provide Syntactic Support for Meta-Programming

  3. A Meta-Program in Scheme (define (run code) (eval code nil)) (define (power n x)(if (= n 0) 1 `(* ,x ,(power (- n 1) x)))) ;;; (power 2 ‘x)yields (* x (* x 1)) (define square(run `(lambda (x) ,(power 2 ‘x)))) ;;; (power 3 ‘y)yields(* y (* y (* y 1))) (define cube(run `(lambda (y) ,(power 3 ‘y))))

  4. A Meta-Program in MetaML (* <t>: the type for code of type t *) (* run is a built-in function of type: a.<a>a *) fun power (n: int) (x: <int>): <int> =if n = 0 then <1>else <~x * ~(power (n-1) x)> val square: int  int = run <fn x => ~(power 2 <x>)> val cube: int  int = run <fn y => ~(power 3 <y>)>

  5. Scheme vs. MetaML • Scheme is untyped but MetaML is typed • The type system of MetaML can be of great use in ruling out ill-staged meta-programs • The syntax supporting meta-programming can be “translated away” in Scheme but not in MetaML • For instance,(define (power n x) (if (= n 0) 1 `(* ,x ,(power (- n 1) x))))can really be defined as follows:(define (power n x) (if (= n 0) 1 (list ‘* x (power (- n 1) x))))

  6. Higher-Order Abstract Syntax • In essence, it uses functions in the meta-language to represent functions in the object-language • For instance, we can declare a datatype in ML as follows to represent pure untyped lambda-expressions:datatype exp = Lam of (exp  exp) | App of exp * exp • As an example, the l-expressionlx. ly.y(x)is represented as follows in ML:Lam(fn x => Lam (fn y => App (y, x)))

  7. Typeful H.O.A.S. HOAS: a unary type constructor (t) HOAS: the type for the representation of a closed object- program of type t HOASlam: a.b. (aHOASbHOAS)  (ab) HOAS HOASapp: a.b. (ab) HOAS* aHOASbHOAS For instance, the simply typed l-expression lx:int. ly:int  int.y(x) is represented as follows:HOASlam(fn x: int HOAS => HOASlam (fn y: (int  int) HOAS => HOASapp (y, x))) which is given the type (int  (int  int)  int) HOAS.

  8. Weak Head Normalization As an example, we can implement the following function whnf to compute the weak head normal form of a given l-expression: fun whnf (t as HOASlam _) = t| whnf (HOASapp (t1, t2)) = (case whnf t1 of HOASlam f => whnf (f t2) | t1 as HOASapp _ => HOASapp (t1, t2)) withtype {‘a}. ‘a HOAS  ‘a HOAS The invariant that weak head normalization is type-preserving is captured here. Notice that HOASlam(whnf) does not represent anyl-expression (of type (‘a  ‘a) HOAS )

  9. A Difficulty with H.O.A.S. • With h.o.a.s., it often seems inherently difficult to represent object-programs containing free variables • On the other hand, it also seems that there is a genuine need for dealing with open code in meta-programming • For instance, in the following MetaML program:<fn x => ~(power 2 <x>)>the expression power 2 <x> is open code.

  10. Free Variable Evaluation • With h.o.a.s., there is a difficult issue involving compiling/evaluating object-programs containing free variables. • For instance, this issue occurs when we compile the following object-program, HOASlam(fn x: (int HOAS) HOAS => run x)which can also be written as follows in MetaML syntax:<fn x: <int> => ~(run <x>)>

  11. First-Order Abstract Syntax • We can declare the following datatype in ML to represent untyped l-expressions:datatype exp = One | Shi of exp | Lam of exp | App of exp*exp For instance, the l-expression lx.ly.y(x) is now represented as follows:Lam (Lam (App(One, Shi (One))))

  12. Typeful F.O.A.S. FOAS:A binary type constructor (G,t) FOAS:The type for the representation of an object-program of type tin which free program variables are assigned types by G, which is represented as a sequence of types. FOASone:g.a.b. (a::g, a)FOAS FOASshi:g.a.b. (g, b) FOAS (a::g, b)FOAS FOASlam:g.a.b. (a::g, b)FOAS(g, a  b)FOAS FOASapp:g.a.b.(g, a  b)FOAS *(g, a)FOAS  (g, b)FOAS For instance, the simply typed l-expressionlx:int.ly:int  int.y(x) is represented as follows, FOASlam(FOASlam(FOASapp(FOASone,FOASshi(FOASone)))) which can be assigned the type(e,int  (int  int)  int) FOAS

  13. The Syntax for lcode kindsk ::= type | env types t ::= a| t1t2 | G, t | a: type.t| g: env.t type env. G ::= g| e | t :: G const. fun.cf ::= run const. con.cc::= Lift| One |Shi| Lam | App| Fix expr. e ::= … values v ::= … expr. var. ctx. G ::= | G, x : t type. var. ctx. D ::= | D, a :type| D, g : env

  14. Code Constructors in lcode We assign the following types to the code constructors in lcode: Lift: g.a. a g, a One: g.aa::g, a Shi:g.a.b.g, ba::g, b Lam: g.a.b.a::g, bg, a b App: g.a.b. (g, a  b,g, a) g, b  Fix: g.a.a::g, a g, a

  15. The function run in lcode We can now assign the special function run the following type: run : a.e, a  a That is, only closed program is allowed to be run!

  16. A Staged Program in lcode As an example, we can implement a staged power function as follows: fun mult (x: int) (y: int): int = x * y fun power (n: int) (x: <g, int>): <g, int> =if n = 0 then Lift (1)else App (App (Lift mult, x), power (n-1) x) We can then implement the square function as follows: val square: int  int = run (Lam (power 2 One))

  17. Meta-Programming Syntax • It is at least inconvenient, if not impractical, to construct meta-programs with abstract syntax trees. • This situation is further worsened when de Bruijn indexes are used to represent program variables. • To address the issue, we provide • meta-programming syntax to facilitate the construction of meta-programs • a translation that can “translate away” meta-programming syntax

  18. l+ code Extending lcode to l+ code Someadditionalsyntax in : expr. e ::= … | `(e) | ^(e) expr. var. ctx. G ::=| G, x@k: t A typing judgment is of the form D;G|k e : t whereGis a finite mapping from positive integers to type environments such that the domain of G is always equal to the set{1,…,k}. G

  19. G+G D;G | k+1e : t G D;G |k`(e) : <G(k+1;G), t> G D;G |ke : <G(k+1;G), t> G+G D;G | k+1^(e) : t Some Typing Rules in l+ code The typing rule for encoding: The typing rule for decoding:

  20. Translating l+ into lcode (1) code Some generalized code constructors: Liftn :g1…gn .a .a  <g1,…,gn ; a> Lamn :g1…gn .a.b. <g1,…, a :: gn ; b>  <g1,…,gn ; a  b> Appn :g1…gn .a.b.<g1,…,gn ; a  b> <g1,…,gn ; a>  <g1,…,gn ; b> Onen :g1…gn .a .<g1,…, a :: gn ; a> Shin :g1…gn .a.b. <g1,…,gn ; b>  <g1,…,a :: gn ; b> where we use<g1,…,gn ; a> for <g1,<…<gn, a>...>>

  21. Translating l+ into lcode (2) code trans0(xs; x) = x if x@0 is in xs trans0(xs; lam x.e) = lam x. trans0(xs,x@0; e) trans0(xs; e1 (e2)) = (trans0(xs; e1))(trans0(xs; e2)) trans0(xs; `(e)) = trans1(xs; e) … trans1(xs; x) = Lift (x) if x@0 is in xs trans1(xs; x) = var1(xs, x) if x@1 is in xs trans1(xs; lam x.e) = Lam x. trans1(xs,x@1; e) trans1(xs; e1 (e2)) = App(trans1(xs; e1),trans1(xs; e2)) trans1(xs; `(e)) = trans2(xs; e) trans1(xs; ^(e)) = trans0(xs; e) …

  22. |0  Translating l+ into lcode(3) code The main technical result of the paper: Theorem Assume that ; e : t is derivable. Then ; |trans(e) : t is also derivable, wheretrans(e) = trans0(; e)

  23. Some Remarks • Bound variables at stage k>0 • Let e = `(lam x. ^(f `x)) for some function f. Then we havetrans(e)=Lam (f One) • f is the identity function lam x. x :trans(e)reduces toLam (One) • fis the shifting functionlam x. Shi (x) :trans(e)reduces toLam (Shi One) • fis the lifting function lam x. Lift (x) :trans(e)reduces toLam (Lift One) • Cross-Stage Persistence (CSP) operator % • % can be defined as ^Lift • Lift can be defined as `%

  24. Some Closely Related Work • MetalML (Sheard andTaha) • Imperative MetaML (Calcagno et al ) • Environment Classifier (Taha and Nielsen) • Staged Computation (Davis and Pfenning) • Meta-Programming with Names and Necessities (Nanevski and Pfenning) • Guarded Recursive Datatypes (Xi et al )

  25. End of the Talk • Thank You! Questions?

More Related