Download presentation
Presentation is loading. Please wait.
1
1 Meta-Programming through Typeful Code Representation Chiyan Chen and Hongwei Xi Boston University
2
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
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
4 A Meta-Program in MetaML (* : the type for code of type (* run is a built-in function of type: *) fun power (n: int) (x: ): = if n = 0 then else val square: int int = run ~(power 2 )> val cube: int int = run ~(power 3 )>
5
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
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 -expression x. y.y(x) is represented as follows in ML: Lam(fn x => Lam (fn y => App (y, x)))
7
7 Typeful H.O.A.S. HOAS : a unary type constructor ( ) HOAS : the type for the representation of a closed object- program of type HOASlam : . . ( HOAS HOAS ) ( ) HOAS HOASapp : . . ( ) HOAS HOAS HOAS For instance, the simply typed -expression x:int. y: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
8 Weak Head Normalization As an example, we can implement the following function whnf to compute the weak head normal form of a given -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 any -expression (of type (‘a ‘a) HOAS )
9
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: ~(power 2 )> the expression power 2 is open code.
10
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: => ~(run )>
11
11 First-Order Abstract Syntax We can declare the following datatype in ML to represent untyped -expressions: datatype exp = One | Shi of exp | Lam of exp | App of exp exp For instance, the -expression x. y.y(x) is now represented as follows: Lam (Lam (App(One, Shi (One))))
12
12 Typeful F.O.A.S. FOAS : A binary type constructor ( G, ) FOAS : The type for the representation of an object-program of type in which free program variables are assigned types by G, which is represented as a sequence of types. FOASone: . . ( FOAS FOASshi: . . ( FOAS FOAS FOASlam: . . ( FOAS FOAS FOASapp: . . FOAS FOAS FOAS For instance, the simply typed l-expression x:int. y:int int.y(x) is represented as follows, FOASlam(FOASlam(FOASapp(FOASone, FOASshi(FOASone)))) which can be assigned the type ( ,int (int int) int) FOAS
13
13 The Syntax for code kinds ::= type | env types ::= | 1 2 | G, | type | env type env. G | | G const. fun. cf ::= run const. con. cc ::= Lift | One | Shi | Lam | App | Fix expr. e ::= … values v ::= … expr. var. ctx. ::= | x type. var. ctx. ::= | type | env
14
14 Code Constructors in code We assign the following types to the code constructors in code: Lift: . , One: . , Shi: . . , , Lam: . . , , App: . . ( , , , ) , Fix: . , ,
15
15 The function run in code We can now assign the special function run the following type: run : , That is, only closed program is allowed to be run!
16
16 A Staged Program in code 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: ): = 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
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
18 Extending code to Some additional syntax in : expr. e ::= … | `(e) | ^(e) expr. var. ctx. ::= | x @ k A typing judgment is of the form ; | k e : where G is a finite mapping from positive integers to type environments such that the domain of G is always equal to the set {1,…,k}. code G +
19
19 Some Typing Rules in The typing rule for encoding: The typing rule for decoding: code | k `(e) : G | k+1 e : G + G | k e : G | k+1 ^(e) : G + G
20
20 Translating into code (1) Some generalized code constructors: Lift n : 1 … n. . 1,…, n ; Lam n : 1 … n. . . 1,…, :: n ; 1,…, n ; App n : 1 … n. . . 1,…, n ; 1,…, n ; 1,…, n ; One n : 1 … n. . 1,…, :: n ; Shi n : 1 … n. . . 1,…, n ; 1,…, n ; where we use 1,…, n ; for 1, … n, code
21
21 Translating into code (2) trans 0 (xs; x) = x if x@0 is in xs trans 0 (xs; lam x.e) = lam x. trans 0 (xs,x@0; e) trans 0 (xs; e 1 (e 2 )) = (trans 0 (xs; e 1 ))(trans 0 (xs; e 2 )) trans 0 (xs; `(e)) = trans 1 (xs; e) … trans 1 (xs; x) = Lift (x) if x@0 is in xs trans 1 (xs; x) = var 1 (xs, x) if x@1 is in xs trans 1 (xs; lam x.e) = Lam x. trans 1 (xs,x@1; e) trans 1 (xs; e 1 (e 2 )) = App(trans 1 (xs; e 1 ),trans 1 (xs; e 2 )) trans 1 (xs; `(e)) = trans 2 (xs; e) trans 1 (xs; ^(e)) = trans 0 (xs; e) … code
22
22 Translating into code (3) The main technical result of the paper: Theorem Assume that ; e : is derivable. Then ; | trans(e) : is also derivable, where trans(e) = trans 0 ( ; e) code | 0
23
23 Some Remarks Bound variables at stage k>0 Let e = `(lam x. ^(f `x)) for some function f. Then we have trans(e)=Lam (f One) f is the identity function lam x. x : trans(e) reduces to Lam (One) f is the shifting function lam x. Shi (x) : trans(e) reduces to Lam (Shi One) f is the lifting function lam x. Lift (x) : trans(e) reduces to Lam (Lift One) Cross-Stage Persistence (CSP) operator % % can be defined as ^Lift Lift can be defined as `%
24
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
25 End of the Talk Thank You! Questions?
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.