在 GitHub 上编辑此页面

对称元编程的元理论

本笔记介绍了 原则性元编程 的简化变体,并概述了其健全性证明。该变体仅处理两个阶段之间的对话。程序可以包含引号,引号中可以包含拼接(拼接中可以包含引号,引号中可以包含拼接,等等)。或者程序可以从包含嵌入引号的拼接开始。本质上的限制是 (1) 一个术语可以包含顶层引号或顶层拼接,但不能同时包含两者,以及 (2) 引号不能直接出现在引号内,拼接不能直接出现在拼接内。换句话说,宇宙仅限于两个阶段。

在这个限制下,我们可以简化类型规则,使之始终只有两个环境,而不是拥有一个环境堆栈。这里介绍的变体与完整演算的不同之处还在于,我们用上下文类型规则替换了求值上下文。虽然这更冗长,但它使建立元理论变得更容易。

语法

Terms         t  ::=  x                 variable
                      (x: T) => t       lambda
                      t t               application
                      ’t                quote
                      ~t                splice

Simple terms  u  ::=  x  |  (x: T) => u  |  u u

Values        v  ::=  (x: T) => t       lambda
                      ’u                quoted value

Types         T  ::=  A                 base type
                      T -> T            function type
                      ’T                quoted type

操作语义

求值

            ((x: T) => t) v  -->  [x := v]t

                         t1  -->  t2
                       ---------------
                       t1 t  -->  t2 t

                         t1  -->  t2
                       ---------------
                       v t1  -->  v t2

                         t1  ==>  t2
                        -------------
                        ’t1  -->  ’t2

拼接

                        ~’u  ==>  u

                         t1  ==>  t2
               -------------------------------
               (x: T) => t1  ==>  (x: T) => t2

                         t1  ==>  t2
                       ---------------
                       t1 t  ==>  t2 t

                         t1  ==>  t2
                       ---------------
                       u t1  ==>  u t2

                         t1  -->  t2
                        -------------
                        ~t1  ==>  ~t2

类型规则

类型判断的形式为 E1 * E2 |- t: T,其中 E1, E2 是环境,*~ 之一。

                          x: T in E2
                       ---------------
                       E1 * E2 |- x: T


                   E1 * E2, x: T1 |- t: T2
               --------------------------------
               E1 * E2 |- (x: T1) => t: T -> T2


         E1 * E2 |- t1: T2 -> T    E1 * E2 |- t2: T2
         -------------------------------------------
                     E1 * E2 |- t1 t2: T


                       E2 ’ E1 |- t: T
                      -----------------
                      E1 ~ E2 |- ’t: ’T


                       E2 ~ E1 |- t: ’T
                       ----------------
                       E1 ’ E2 |- ~t: T

(有趣的是,这看起来有点像圣诞树)。

健全性

元理论通常需要对两个判断进行相互归纳。

进展定理

  1. 如果 E1 ~ |- t: T,则要么 t = v,其中 v 是某个值,要么 t --> t2,其中 t2 是某个项。
  2. 如果 ’ E2 |- t: T,则要么 t = u,其中 u 是某个简单项,要么 t ==> t2,其中 t2 是某个项。

通过对项进行结构归纳证明。

为了证明 (1)

  • 变量、lambda 和应用的情况与 STLC 中的情况相同。
  • 如果 t = ’t2,则根据反演,我们有 ’ E1 |- t2: T2,其中 T2 是某个类型。根据第二个 归纳假设 (I.H.),我们有以下两种情况之一:
    • t2 = u,因此 ’t2 是一个值。
    • t2 ==> t3,因此 ’t2 --> ’t3
  • 情况 t = ~t2 不可类型化。

为了证明 (2)

  • 如果 t = x,则 t 是一个简单项。

  • 如果 t = (x: T) => t2,则要么 t2 是一个简单项,在这种情况下 t 也是一个简单项。要么根据第二个 I.H. t2 ==> t3,在这种情况下 t ==> (x: T) => t3

  • 如果 t = t1 t2,则以下三种情况之一适用:

    • t1t2 是一个简单项,则 t 也是一个简单项。
    • t1 不是一个简单项。然后根据第二个 I.H.,t1 ==> t12,因此 t ==> t12 t2
    • t1 是一个简单项,但 t2 不是。然后根据第二个 I.H. t2 ==> t22,因此 t ==> t1 t22
  • 情况 t = ’t2 不可类型化。

  • 如果 t = ~t2,则根据反演,我们有 E2 ~ |- t2: ’T2,其中 T2 是某个类型。根据第一个 I.H.,我们有以下两种情况之一:

    • t2 = v。由于t2: ’T2,我们必须有v = ’u,其中u是一个简单项,因此t = ~’u。通过引号拼接归约,t ==> u
    • t2 --> t3。然后根据’t的上下文规则,t ==> ’t3

替换引理

  1. 如果E1 ~ E2 |- s: SE1 ~ E2, x: S |- t: T,则E1 ~ E2 |- [x := s]t: T
  2. 如果E1 ~ E2 |- s: SE2, x: S ’ E1 |- t: T,则E2 ’ E1 |- [x := s]t: T

证明是通过对t的类型推导进行归纳,类似于 STL 的证明(其中(2)比(1)更简单,因为我们不需要将 lambda 绑定与绑定变量x交换)。连接两个假设的论据如下。

为了证明(1),令t = ’t1。然后T = ’T1,其中T1是某种类型,最后一个类型规则是

                    E2, x: S ’ E1 |- t1: T1
                   -------------------------
                   E1 ~ E2, x: S |- ’t1: ’T1

根据第二个归纳假设,E2 ’ E1 |- [x := s]t1: T1。根据类型,E1 ~ E2 |- ’[x := s]t1: ’T1。由于[x := s]t = [x := s](’t1) = ’[x := s]t1,我们得到[x := s]t: ’T1

为了证明(2),令t = ~t1。然后最后一个类型规则是

                    E1 ~ E2, x: S |- t1: ’T
                    -----------------------
                    E2, x: S ’ E1 |- ~t1: T

根据第一个归纳假设,E1 ~ E2 |- [x := s]t1: ’T。根据类型,E2 ’ E1 |- ~[x := s]t1: T。由于[x := s]t = [x := s](~t1) = ~[x := s]t1,我们得到[x := s]t: T

保持定理

  1. 如果E1 ~ E2 |- t1: Tt1 --> t2,则E1 ~ E2 |- t2: T
  2. 如果E1 ’ E2 |- t1: Tt1 ==> t2,则E1 ’ E2 |- t2: T

证明是通过对评估推导进行结构归纳。证明(1)类似于 STL 的证明,使用替换引理来处理 beta 归约情况,并添加了对引号项的归约,过程如下

  • 假设最后一个规则是
                        t1  ==>  t2
                       -------------
                       ’t1  -->  ’t2
    

    根据类型规则的反演,我们必须有 T = ’T1,其中 T1 是一个类型,使得 t1: T1。根据第二个归纳假设,t2: T1,因此 ’t2:T1`。

为了证明 (2)

  • 假设最后一个规则是 ~’u ==> u~’u 的类型证明必须具有以下形式

                      E1 ’ E2 |- u: T
                     -----------------
                     E1 ~ E2 |- ’u: ’T
                     -----------------
                     E1 ’ E2 |- ~’u: T
    

    因此,E1 ’ E2 |- u: T

  • 假设最后一个规则是

                          t1  ==>  t2
                -------------------------------
                (x: S) => t1  ==>  (x: T) => t2
    

    根据类型反演,E1 ' E2, x: S |- t1: T1,其中 T1 是一个类型,使得 T = S -> T1。根据归纳假设,t2: T1。根据 lambda 表达式的类型规则,结果成立。

  • 应用的上下文规则同样简单明了。

  • 假设最后一个规则是

                          t1  ==>  t2
                         -------------
                         ~t1  ==>  ~t2
    

    根据类型规则的反演,我们必须有 t1: ’T。根据第一个归纳假设,t2: ’T,因此 ~t2: T