简单类型Lambda演算(3)

之前讨论的都是狭义上的STLC,广义上往往还包括一些STLC的扩展类型和扩展语法。

0X00 let 绑定

这个在ML系的语言中非常的常见, Haskell中也有这个东西。简单的说就是给一些重复出现的东西取一个别称。在OCaml ,这里的操作语义一般是使用标准的"call-by-value".

语法

  (* let *)
  | tlet : string -> tm -> tm -> tm
   (* i.e., let x = t1 in t2 *)

操作语义:

    (* let *)
    | ST_Let1 : ∀ x t1 t1' t2,
        t1 --> t1' ->
        (tlet x t1 t2) --> (tlet x t1' t2)
    |ST_LetValue : ∀ x v1 t2,
        value v1 ->
        (tlet x v1 t2) --> (subst x v1 t2)

我们这里和OCaml类似使用先对let中定义的绑定内容求值,再带入的做法(call by value)

替换规则

    (* let *)
    (* if x = y, nothing need to be changed in body*)
    | tlet y t1 t2 =>
      tlet y (subst x s t1) (if eqb_string x y then t2 else (subst x s t2))

类型关系

| T_Let : ∀ Gamma x t1 t2 T1 T2,
        Gamma ⊢ t1 ∈ T1 ->
        (x |-> T1; Gamma) ⊢ t2 ∈ T2 ->
        Gamma ⊢ (tlet x t1 t2) ∈ T2

参考Abs这个其实不是很难写,不过我第一次写的时候没有更新上下文,导致后面证明过程中卡了好久。。。。。还是理解不到位。

0X01 元组(对)

sf里面把这个称做Pair,有不少语言里也叫tuple一个意思.基本上就是lisp里面那个,表示一个值对,fst可以访问左侧的值,snd可以取出右侧的值。

Example

\x : Nat*Nat.
          let sum = x.fst + x.snd in
          let diff = x.fst - x.snd in
          (sum,diff)

语法

(* pairs *)
  | pair : tm -> tm -> tm
  | fst : tm -> tm
  | snd : tm -> tm

值关系

| v_pair : ∀ v1 v2,
        value v1 ->
        value v2 ->
        value (pair v1 v2).

操作语义

(* pairs *)
    | ST_Pair1 : ∀ t1 t2 t1',
        t1 --> t1' ->
        (pair t1 t2) --> (pair t1' t2)
    | ST_Pair2 : ∀ t1 t2 t2',
        t2 --> t2' ->
        (pair t1 t2) --> (pair t1 t2')
    | ST_Fst1 : ∀ t1 t1',
        t1 --> t1' ->
        (fst t1) --> (fst t1')
    | ST_FstPair : ∀ v1 v2,
        value v1 ->
        value v2 ->
        (fst (pair v1 v2)) --> v1
    | ST_Snd1 : ∀ t1 t1',
        t1 --> t1' ->
        (snd t1) --> (snd t1')
    | ST_SndPair : ∀ v1 v2,
        value v1 ->
        value v2 ->
        (snd (pair v1 v2)) --> v2

类型关系

    (* pairs *)
    | T_Pair : ∀ Gamma t1 t2 T1 T2,
        Gamma |- t1 ∈ T1 ->
        Gamma |- t2 ∈ T2 ->
        Gamma |- (pair t1 t2) ∈ (Prod T1 T2)
    | T_Fst : ∀ Gamma t T1 T2,
        Gamma |- t ∈ (Prod T1 T2) ->
        Gamma |- (fst t) ∈ T1
    | T_Snd : ∀ Gamma t T1 T2,
        Gamma |- t ∈ (Prod T1 T2) ->
        Gamma |- (snd t) ∈ T2

这中Pair的类型也被称为积类型(Product Type),记作Nat * Nat,不难理解,相当于两个集合的卡式积。

替换规则

(* lists *)
    | tnil T =>
           tnil T
    | tcons t1 t2 =>
            tcons (subst x s t1) (subst x s t2)
    | tlcase t1 t2 y1 y2 t3 =>
             tlcase (subst x s t1) (subst x s t2) y1 y2
             (if eqb_string x y1 then
                t3
              else if eqb_string x y2 then t3
                   else (subst x s t3))

0X02 和类型

有的时候我们希望一个变量可以在不同的情况下拥有不同的类型, 比如c语言就提供了union,Java,Rust之类的语言可能会没有联合体,但是往往也会在标准库之类的东西里提供Either类之类的工具,这个在表示异常的时候会比较有效,go这种把err直接放到tuple里返回的,在我看来逻辑上就很怪异.....

STLC中我们定义inl为取左侧类型,inr取右侧类似, 使用case关键字可以对取不同类型时候的情况进行匹配。

Example

getNat ∈ Nat+Bool -> Nat
    getNat =
      \x:Nat+Bool.
        case x of
          inl n => n
        | inr b => test b then 1 else 0

值关系

(* A tagged value is a value:  *)
    | v_inl : forall v T,
        value v ->
        value (tinl T v)
    | v_inr : forall v T,
        value v ->
        value (tinr T v)

语法

(* sums *)
  | tinl : ty -> tm -> tm
  | tinr : ty -> tm -> tm
  | tcase : tm -> string -> tm -> string -> tm -> tm

操作语义

(* sums *)
    | ST_Inl : ∀ t1 t1' T,
        t1 --> t1' ->
        (tinl T t1) --> (tinl T t1')
    | ST_Inr : ∀ t1 t1' T,
        t1 --> t1' ->
        (tinr T t1) --> (tinr T t1')
    | ST_Case : ∀ t0 t0' x1 t1 x2 t2,
        t0 --> t0' ->
        (tcase t0 x1 t1 x2 t2) --> (tcase t0' x1 t1 x2 t2)
    | ST_CaseInl : ∀ v0 x1 t1 x2 t2 T,
        value v0 ->
        (tcase (tinl T v0) x1 t1 x2 t2) --> [x1:=v0]t1
    | ST_CaseInr : ∀ v0 x1 t1 x2 t2 T,
        value v0 ->
        (tcase (tinr T v0) x1 t1 x2 t2) --> [x2:=v0]t2

替换规则

(* sums *)
    | tinl T t1 =>
           tinl T (subst x s t1)
    | tinr T t1 =>
           tinr T (subst x s t1)
    | tcase t0 y1 t1 y2 t2 =>
            tcase (subst x s t0)
            y1 (if eqb_string x y1 then t1 else (subst x s t1))
            y2 (if eqb_string x y2 then t2 else (subst x s t2))

类型关系

(* sums *)
    | T_Inl : ∀ Gamma t1 T1 T2,
        Gamma |- t1 ∈ T1 ->
        Gamma |- (tinl T2 t1) ∈ (Sum T1 T2)
    | T_Inr : ∀ Gamma t2 T1 T2,
        Gamma |- t2 ∈ T2 ->
        Gamma |- (tinr T1 t2) ∈ (Sum T1 T2)
    | T_Case : ∀ Gamma t0 x1 T1 t1 x2 T2 t2 T,
        Gamma |- t0 ∈ (Sum T1 T2) ->
        (update Gamma x1 T1) |- t1 ∈ T ->
        (update Gamma x2 T2) |- t2 ∈ T ->
        Gamma |- (tcase t0 x1 t1 x2 t2) ∈ T

0X03 Unit

这个其实就相当于空指针的null类型,这是一个只有一个元素的类型。

操作语义
这个东西没法再步进了

值关系

| v_unit : value unit

类型关系

| T_Unit : forall Gamma,
        Gamma |- unit ∈ Unit

0X04 列表List

lisp like list没什么好多说的, nil表示空, cons表示后继; 和haskell,ml一样,这里支持对list进行模式匹配。不过话说这个东西其实可以用前面说的product type来模拟,毕竟pair只要一遍放值一边放后继其实也差不多,毕竟都是二元。

Example

\x:List Nat.
      lcase x of nil   => 0
               | a::x' => lcase x' of nil    => a
                                    | b::x'' => a+b
 (* lists *)
  | tnil : ty -> tm
  | tcons : tm -> tm -> tm
  | tlcase : tm -> tm -> string -> string -> tm -> tm

值关系

(* A list is a value iff its head and tail are values: *)
    | v_lnil : ∀ T, value (tnil T)
    | v_lcons : ∀ v1 vl,
        value v1 ->
        value vl ->
        value (tcons v1 vl)

操作语义

(* lists *)
    | ST_Cons1 : ∀ t1 t1' t2,
        t1 --> t1' ->
        (tcons t1 t2) --> (tcons t1' t2)
    | ST_Cons2 : ∀ v1 t2 t2',
        value v1 ->
        t2 --> t2' ->
        (tcons v1 t2) --> (tcons v1 t2')
    | ST_Lcase1 : ∀ t1 t1' t2 x1 x2 t3,
        t1 --> t1' ->
        (tlcase t1 t2 x1 x2 t3) --> (tlcase t1' t2 x1 x2 t3)
    | ST_LcaseNil : ∀ T t2 x1 x2 t3,
        (tlcase (tnil T) t2 x1 x2 t3) --> t2
    | ST_LcaseCons : ∀ v1 vl t2 x1 x2 t3,
        value v1 ->
        value vl ->
        (tlcase (tcons v1 vl) t2 x1 x2 t3)
          --> (subst x2 vl (subst x1 v1 t3))

替换规则

(* lists *)
    | tnil T =>
           tnil T
    | tcons t1 t2 =>
            tcons (subst x s t1) (subst x s t2)
    | tlcase t1 t2 y1 y2 t3 =>
             tlcase (subst x s t1) (subst x s t2) y1 y2
             (if eqb_string x y1 then
                t3
              else if eqb_string x y2 then t3
                   else (subst x s t3))

类型规则

 (* lists *)
    | T_Nil : ∀ Gamma T,
        Gamma |- (tnil T) ∈ (List T)
    | T_Cons : ∀ Gamma t1 t2 T1,
        Gamma |- t1 ∈ T1 ->
        Gamma |- t2 ∈ (List T1) ->
        Gamma |- (tcons t1 t2) ∈ (List T1)
    | T_Lcase : ∀ Gamma t1 T1 t2 x1 x2 t3 T2,
        Gamma |- t1 ∈ (List T1) ->
        Gamma |- t2 ∈ T2 ->
        (update (update Gamma x2 (List T1)) x1 T1) |- t3 ∈ T2 ->
        Gamma |- (tlcase t1 t2 x1 x2 t3) ∈ T2

0X05 递归

为了实现可以验证的递归操作,直接使用带递归的函数显然是不行的。这里使用类似Coq中Fixpoint的做法。
引入fix操作符, 不再把递归函数看成函数,其类型为fix。实现的要点在于为了能够在fix操作步进的过程中不断的进行打开,需要把fix 内做一个包裹的函数,其输入和输出类型变得一致,这样就能在验证过程中通过大量的unfold操作(不停的添加函数抽象,替换入函数体 )把递归函数展开成一个一层套一层的函数。

Example

fact =
          fix
            (\f:Nat->Nat.
               \x:Nat.
                  test x=0 then 1 else x * (f (pred x)))

操作语义

(* fix *)
    | ST_Fix1 : ∀ t1 t1',
        t1 --> t1' ->
        (tfix t1) --> (tfix t1')
    | ST_FixAbs : ∀ xf t2 T1,
        (tfix (abs xf T1 t2)) -->
        (subst xf (tfix (abs xf T1 t2)) t2)

替换规则

(* fix *)
    | tfix t1 =>
      tfix (subst x s t1)

类型关系

(* fix *)
    | T_Fix : ∀ Gamma t1 T1,
        Gamma |- t1 ∈ (Arrow T1 T1) ->
        Gamma |- (tfix t1) ∈ T1

0X06 Record类型

这个和haskell里的record差不多, 在c里的话就是结构体。使用 . 操作符可以把以一个record中某个Lable的值给取出来

Example

a:
{i1:T1, ..., in:Tn}       
                   
a . i1

这里可以把record 作为pair + list的语法糖来实现, 简单的说就是list里放一堆pair, fst是label, snd是值。


这一章节大部分的证明和定义我都写完了,完整的代码在这,证明性质的code 和过程比较长,但是和之前并没有本质区别:
https://github.com/StarGazerM/my-foolish-code/blob/master/plf/MoreStlc.v

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,319评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,801评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,567评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,156评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,019评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,090评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,500评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,192评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,474评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,566评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,338评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,212评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,572评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,890评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,169评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,478评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,661评论 2 335

推荐阅读更多精彩内容