• Aucun résultat trouvé

In this section we show how to perform CPS conversion onλH while still pre-serving proofs represented in the type system. This stage transforms all uncon-ditional control transfers, including function invocation and return, to function calls and gives explicit names to all intermediate computations. In this way, evaluation order is explicit and there is no need for a control stack.

There are two interesting points in our approach to CPS conversion. First, as we discuss in detail later in this section, arbitrary terms of the type lan-guage that appear in computation terms are not transformed. Second, the transformation of types is encoded as a function in our type language and, as will become apparent later in this section, this fact is important for proving that our CPS conversion is type-correct.

We start by defining a version ofλH using type-annotated terms. Byf¯and

¯

e we denote the terms without annotations. Type annotations allow us to present the CPS transformation based on syntactic instead of typing deriva-tions.

(exp) e ::= ¯eA

¯

e ::=x|n|tt|ff|f |fixx:A. f |e e0 |e[A]| hX=A, e:A0i

|openeashX, xiine0| he0, . . . en1i |sel[A](e, e0)

|eaope0|ecope0|if [A, A0](e, X1. e1, X2. e2) (fun) f ::= ¯fA

f¯::=λx:A. e|ΛX:A. f

We call the target calculus for this phaseλK, with syntax:

(val) v::=x|n|tt|ff| hX=A, v:A0i | hv0, . . . vn−1i

|fixx0[X1:A1, . . . Xn:An](x:A). e

(exp) e::=v[A1, . . . An](v0)|letx=vine|lethX, xi=openvine

|letx=sel[A](v, v0)ine|letx=vaopv0 ine|letx=vcopv0ine

|if [A, A0](v, X1. e1, X2. e2)

Expressions inλK consist of a series ofletbindings followed by a function ap-plication or a conditional branch. There is only one abstraction mechanism, fix, which combines type and value abstraction. Multiple arguments may be passed by packing them in a tuple. We use the following syntactic sugar to denote non-recursive function definitions and value applications inλK(herex0 is a fresh variable):

λx:A. e ≡ fixx0[](x:A). e v v0 ≡ v[](v0)

ΛX1:A1. . . .ΛXn:An. λx:A. e ≡ fixx0[X1:A1, . . . Xn:An](x:A). e λKshares the TL type language withλH. The types forλKall have kindΩK

which, as inλH, is an inductive kind defined in TL. TheΩK kind has all the constructors ofΩplus one more (func). Since functions in CPS do not return values, the function type constructor ofΩK has a different kind:

→→ : ΩK→ΩK

We use the more conventional syntaxA→⊥for→→A(i.e.,the type of functions taking a parameter of typeA). As will become apparent shortly in the static se-mantics ofλK, no value ofλK has typeA→⊥. The latter is used in conjunction with the new constructorfuncto form the types of function values:

func : ΩK→ΩK

Every function value is implicitly associated with a closure environment (for all the free variables), so thefuncconstructor is useful in the closure-conversion phase (see Section 6). In the case of function values, the type parameter of func is an element ofΩK constructed by application of →→, ∀∀Kind or∀∀Kscm. The func constructor allows us to build one closure for each polymorphic function definition (even though it contains both type abstraction and term abstraction).

In the static semantics ofλK we use two forms of judgments. As inλH, the judgment∆; Γ `K v :Aindicates that the valuevis well formed and of type Ain the type and value contexts ∆andΓ respectively. Moreover,∆; Γ `K e indicates that the expressione is well formed in ∆ and Γ. In both forms of judgments, we omit the subscript from`K when it can be deduced from the context.

The static semantics ofλKis specified by the formation rules in Figure 6. We omit the rules for environment formation, variables, constants, tuples, pack-ages, and type conversion on values, which are the same as in λH, and we give only one example for arithmetic and comparison operators. Except for the rules K-FIXand K-APP, which must take into account the presence offunc, the static semantics forλKis a natural consequence of the static semantics forλH. Typed CPS conversion involves the translation of both types and computa-tion terms. Earlier algorithms [Harper and Lillibridge 1993; Morrisett et al.

1998] require traversing and transforming every term in the type language (which would include all the proofs in our setting). This is impractical because proofs are large in size, and transforming them can alter their meanings and break the sharing among different intermediate languages.

To see the actual problem, let us convert theλH expressionhX =A, e:Bi to CPS, assuming that it has type∃X:A0. B. We useKtypto denote the meta-level translation function for the type language andKexpfor the computation language. Under previous algorithms, the translation also transforms the wit-nessA:

Kexp[[hX=A, e:Bi]] =

λk:Ktyp[[∃X:A0. B]].Kexp[[e]] (λx:Ktyp[[[A/X]B]].khX=Ktyp[[A]], x:Ktyp[[B]]i) Here we CPS-converteand apply it to a continuation, which puts the result of its evaluation in a package and hands it to the return continuationk. With proper definition ofKtypand assuming that Ktyp[[X]] =X on all variables X, we can show that the two typesKtyp[[[A/X]B]]and[Ktyp[[A]]/X](Ktyp[[B]])are equivalent (under=βηι). Thus the translation preserves typing.

But we do not want to touch the witnessA, so the translation function should

for alli∈ {1. . . n} `Ai:si

∆, X1:A1. . . , Xn:An ` A: Ω ∆, X1:A1. . . , Xn:An; Γ, x0:A0, x:A` e

∆; Γ ` fixx0[X1:A1, . . . Xn:An](x:A). e:A0 whereA0=func(∀s1X1:A1. . . .snXn:An. A→⊥)

(K-FIX)

for alli∈ {1. . . n} `Ai:Bi

∆; Γ`v0:func(∀s1X1:B1. . . .∀snXn:Bn. A→⊥) ∆; Γ ` v: [A1/X1]. . .[An/Xn]A

∆; Γ ` v0[A1, . . . An](v)

(K-APP)

∆; Γ ` v:A ∆; Γ, x:A` e

∆; Γ ` letx=vine (K-VAL)

∆; Γ ` v:tupA00B ∆; Γ ` v0:snatA0 ` A:LTA0A00 ∆; Γ, x:B A0 ` e

∆; Γ ` letx=sel[A](v, v0)ine (K-SEL)

∆; Γ ` v:sY:B. A ∆, X:B; Γ, x: [X/Y]A` e

∆; Γ ` lethX, xi=openvine

X / s6=Ext

(K-OPEN)

∆; Γ ` v:snatA ∆; Γ ` v0:snatA0 ∆; Γ, x:snat(plusA A0) ` e

∆; Γ ` letx=v+v0ine (K-ADD)

∆; Γ ` v:snatA ∆; Γ ` v0:snatA0 ∆; Γ, x:sbool(ltA A0)` e

∆; Γ ` letx=v<v0ine (K-LT)

`B:BoolKind `A:B A0 ∆; Γ ` v:sboolA0

∆, X1:Btrue; Γ` e1 ∆, X2:Bfalse; Γ ` e2

∆; Γ ` if [B, A](v, X1. e1, X2. e2)

(K-IF) Fig. 6. Static semantics ofλK.

be defined as follows:

Kexp[[hX=A, e:Bi]] =

λk:Ktyp[[∃X:A0. B]].Kexp[[e]] (λx:Ktyp[[[A/X]B]].khX=A, x:Ktyp[[B]]i) To preserve typing, we have to make sure that the two types Ktyp[[[A/X]B]]

and[A/X](Ktyp[[B]])are equivalent. This seems impossible to achieve ifKtypis defined at the meta level.

Our solution is to internalize the definition ofKtypin our type language. We replaceKtypby a type function Kof kindΩ→ΩK. For readability, we use the pattern-matching syntax, but it can be easily coded using theElimconstruct.

K(snatt) = snatt K(sboolt) = sboolt

K(t1→t2) = func((K(t1)×Kc(t2))→⊥) K(tupt1t2) = tupt1(λt:Nat.K(t2 t))

K(∀∀Kindk t) = func(∀∀Kindk(λt1:k.Kc(t t1)→⊥)) K(∃∃Kindk t) = ∃∃Kindk(λt1:k.K(t t1))

K(∀∀Kscmz t) = func(∀∀Kscmz(λk:z.Kc(t k)→⊥)) K(∃∃Kscmz t) = ∃∃Kscm z(λk:z.K(t k))

where

Kc≡λt: Ω.func(K(t)→⊥).

The definition ofK is in the spirit of theinterpfunction of Crary and Weirich [1999]. However interpcannot be used in defining a similar CPS conversion, because its domain does not cover (nor is there an injection to it from) all types appearing in type annotations. InλH these types are in the inductive kindΩ and can be analyzed byK. We can now proveK([A/X]B) =βηι[A/X](K(B))by first reducingB to its normal formB0. Clearly,K([A/X]B) =βηι K([A/X]B0) and [A/X](K(B0)) =βηι [A/X](K(B)). Finally, we can show the equivalence K([A/X]B0) =βηι [A/X](K(B0))by induction over the structure of the normal formB0.

The definition of the CPS transformation for computation terms of λH to computation terms of λK is given in Figure 7. As an example of how CPS conversion works, let us consider the transformation of function abstraction (λx:A. e). The result is a function value that takes as a parameter a pairxarg, consisting of the original abstraction’s parameterx and the current continua-tionk. After accessing the two elements of this pair, the function value applies the CPS conversion of the abstraction’s body tok. On the other hand, the trans-formation of a function application(e1e2)gives a function value that takes as a parameter the current continuationk. By applying the CPS conversions ofe1

ande2to appropriate continuations, this function value ultimately applies the function corresponding toe1to a pair consisting of the value corresponding to e2and the continuationk.

The following proposition states that our CPS conversion preserves typing.

As we discussed earlier, it is important for its proof thatKhas been encoded as a function in TL.

Proposition 5.1 (Type Correctness of CPS Conversion) If·;· `H e:A, then·;· `K Kexp[[ ¯eA]] :func(Kc(A)→⊥).

Proof sketch By induction on the typing derivation fore.

Documents relatifs