Windows 实用技巧汇总
平时使用 Windows 时总结的一些实用的小技巧。
平时使用 Windows 时总结的一些实用的小技巧。
为基于 xulrunner 为内嵌 Gecko 程序启用 Profile
auto
- proof searchLtac
- automated forward reasoning (hypothesis matching machinery)eauto
, eapply
- deferred instantiation of existentialsLtac
macro1 | Ltac inv H := inversion H; subst; clear H. |
auto
Tactic
auto
can free us by searching for a sequence of applications that will prove the goal:
1 | intros P Q R H1 H2 H3. |
auto
solves goals that are solvable by any combination of
intros
apply
(of hypotheses from the local context, by default)使用 auto 一定是“安全”的,它不会失败,也不会改变当前证明的状态: auto 要么完全解决它,要么什么也不做。
Proof search could, in principle, take an arbitrarily long time,
so there are limits to how far auto will search by default. (i.e.5
)
1 | Example auto_example_3 : ∀(P Q R S T U: Prop), |
auto
auto considers a hint database of other lemmas and constructors.
common lemmas about equality and logical operators are installed by default.
just for the purposes of one application of
auto
我们可以为某次auto
的调用扩展提示数据库,auto using ...
1 | Example auto_example_6 : ∀n m p : nat, |
1 | Hint Resolve T. |
Proof with auto.
Under Proof with t
, t1...
== t1; t
.
对于很常见的一种矛盾情形:
1 | H1: beval st b = false |
contradiction
并不能解决,必须 rewrite H1 in H2; inversion H2
.
1 | Ltac rwinv H1 H2 := rewrite H1 in H2; inv H2. |
match goal
调用宏1 | Ltac find_rwinv := |
可以看到最后只剩这种改写形式…我们也把他们自动化了:
1 | Ltac find_eqn := |
配合上 repeat
…我们可以 keep doing useful rewrites until only trivial ones are left.
最终效果:
1 | Theorem ceval_deterministic''''': ∀c st st1 st2, |
即使我们给 IMP 加上一个 CRepeat
(其实就是 DO c WHILE b
),
会发现颠倒一下自动化的顺序就能 work 了
1 | induction E1; intros st2 E2; inv E2; |
当然,这种「超级自动化」(hyper-automation) 并不总是现实,也不好调试…
eapply
and eauto
variants推迟量词的实例化
比如对于
1 | Example ceval_example1: |
没有 with
就会 Error: Unable to find an instance for the variable st'
但其实 st'
的取值在后面的步骤是很明显(很好 infer/unify)的,所以 eapply
works.
coqc
module linkingSome module (e.g.Map
) not found
either maunally make map.vo
or proof general can solve that.
How to define the correctness of program transformation, e.g.
optimize_0plus
?
Two
aexps
orbexps
are behaviorally equivalent if they evaluate to the same result in every state.
1 | Definition aequiv (a1 a2 : aexp) : Prop := |
For commands, We can’t simply say … if they evaluate to the same ending state
some commands don’t terminate in any final state at all!
So to define, they either or…
A compact way is
“if the first one terminates in a particular state then so does the second, and vice versa.”
1 | Definition cequiv (c1 c2 : com) : Prop := |
1 | Theorem skip_left : forall c, |
Noticed that the inversion
is like use the inverse function of constructors.
one interesting theorem is that we can prove WHILE <things ⇓ true>
is not terminating.
and is equivalent to any other non-terminating program, e.g. WHILE BTrue DO SKIP END
: (因为我们的「等价」只要求同「发散」即可)
1 | Theorem WHILE_true : ∀b c, |
any number of copies of the body can be “unrolled” without changing meaning
1 | Theorem loop_unrolling : ∀b c, |
x !-> m x ; x
is same map with m
by extenionality!
1 | Theorem identity_assignment : ∀x, |
自反性(reflexive)、对称性(symmetric)和传递性 (transitive)
That is, the equivalence of two subprograms implies the equivalence of the larger programs in which they are embedded
如果两个子程序等价,那么当二者所在的更大的程序中_只有二者不同_时, 这两个更大的程序也等价
aequiv a1 a1'
-----------------------------
cequiv (x ::= a1) (x ::= a1')
cequiv c1 c1'
cequiv c2 c2'
--------------------------
cequiv (c1;;c2) (c1';;c2')
这个术语应该是来自抽象代数 : 能在运算下保持的等价关系
…in the sense that algebraic operations done with equivalent elements will yield equivalent elements.
Congruence relation
1 | Theorem CAss_congruence : ∀x a1 a1', (** cequiv 是集合 commands 上的等价关系 **) |
在 commands 上等价但不同余的关系?
I guess…”both terminating” relation?
which is equivalence relation on commands, but the equivalence would not be maintained after, say C_WHILE
operation.
1 | Example congruence_example: |
A program transformation is sound if it preserves the behavior of the original program.
如果一个程序变换保留了其原始行为,那么它就是_可靠_的
我们可以定义在不同集合 aexp, bexp, com
上的 sound 关系:
(有趣的是,Inductive
定义的非 Prop
的 Type
, 确实就是 Set
, 这是一种 PL 和数学的 Correspondence)
1 | Definition atrans_sound (atrans : aexp → aexp) : Prop := |
An expression is constant when it contains no variable references.
不引用变量的表达式为_常量_
Constant folding is an optimization that finds constant expressions and replaces them by their values.
常量折叠是一种找到常量表达式并把它们替换为其值的优化方法。
aexp
1 | Theorem fold_constants_aexp_sound : |
bexp
证明 btrans_sound fold_constants_bexp.
要难一些,因为其中还用到了 fold_constants_aexp
, 所以我们需要一些技巧
1 | (** 如果不记住而是直接 destruct 的话,这部分信息就丢失了 **) |
cmd
主要技巧在于配合使用 Congruence
与 IH
解决大部分 case,然后分类讨论 fold_constants_bexp
用 sound
做替换解决剩余 case.
类似,但是接下来我们就可以证明先 fold_constants
再 optimize_0plus
也是 sound 的.
这里我更 general 得证明了 ctrans
关系的传递性:
1 | Theorem trans_ctrans_sound : forall tr1 tr2, |
在这个例子中,subst_aexp
是 sound 得,被称为 Constant Propagation (常量传播)
1 | (** [X := 42 + 53](Y + X) => Y + (42 + 53) **) |
所以我们断言这么做是 always sound 得:
1 | Definition subst_equiv_property := ∀x1 x2 a1 a2, |
然而如果 a1
不是常量,副作用很容易让这个转换 unsound
那么怎么证明 ¬subst_equiv_property
(即该性质不成立)? 举一个反例就好
Informal proof
Formal
remember
, then show ⊥
.1 | (** 给出一组反例,使用性质证明他们 cequiv **) |
HAVOC roughly corresponds to an uninitialized variable in a low-level language like C.
After the HAVOC, the variable holds a fixed but arbitrary number.
我们增加一个 HAVOC X
语句(大灾难),会为 X 随机赋一个值…类似于「未初始化变量」
1 | Inductive com : Type := |
also the def of partial function?
solve_by_inverts
in LTac. (used to generate proof)
LTac doesn’t have termination check. (might not be able to find…)
match
is back-tracking point.
number passing in = depth of the iteration/recursion
ST_Plus2
need value v1
. not redundant with ST_Plus1
we might have things not value
but cannot take step as well.
Strong Progress
Normal form
= no relation related to (so cannot step to)
vs Value…
destruct (apply t)
.
can we do that?
Slide Q&A.
value_not_sae_as normal_form
e.g (1+2) + 7
e.g. 3 + 7
One-step
Inf-step -> Inf terms
go from 3 to 3+0
Stuck
No StepR
0 term can step into
Multi-Step Reduction ->*
1 | Inductive multi {X : Type} (R : relation X) : relation X := |
can be either defined as a “head + tail” style (or “tail + head” style), or “refl + trans” style (as in Rel.v
).
the trans
relation are underteministic in terms of the transtive relation using. (you can throw infinitely many trans
constructors in)
having multiple form so we can jump back and forth to pick one easier for proof.
PLT PM lang
multiple smallstep relation can be markded deepner state.qjw
er state.
IMP
astep
no need for `value``
for If
, in PLT we have 2 rules for T/F.
here we can compute…
Par w/o Concurrency is deterministic
(not vice versa)
suddenly / ->* /
tuple
一步到位 : eval to its final value (plus final store)
大步语义只是一个
程序 ↦ 结果
这样的 pair 集合,而「如何一步步处理」才是程序「执行」的本质
not just input state get mapped to output state.
but also intermediate state (which could be observed by concurrent code!)
比如说,大步语义无法区分「不停机」与「卡住」
two quite different reasons of “fail to map a given state to any ending state”
WHILE_true_nonterm
仅仅表达了「程序不能再 take step」,无法与「卡住」区分WHILE_true
更是直接让任何「无限循环」的程序都「等价」了…而忽略了中间状态和 effect (作用)we need a way of presenting semantics that distinguish nontermination from erroneous “stuck states”
更精细化 : a finer-grained way of defining and reasoning about program behaviors.
原子步骤 : “atomic steps” of computation are performed.
Only Constant and Plus
1 | Inductive tm : Type := |
==>
is really ⇓
--------- (E_Const)
C n ==> n
t1 ==> n1
t2 ==> n2
------------------- (E_Plus)
P t1 t2 ==> n1 + n2
single reduction step
find leftmost redex
------------------------------- (ST_PlusConstConst)
P (C n1) (C n2) --> C (n1 + n2)
t1 --> t1'
-------------------- (ST_Plus1)
P t1 t2 --> P t1' t2
t2 --> t2'
---------------------------- (ST_Plus2)
P (C n1) t2 --> P (C n1) t2'
Check notes of
rel
andtactics
for more details about bi-relation.
a.k.a Partial Function.
in terms of its right uniqueness under mathematical context, not its emphasise on partial under programming context)
1 | Definition deterministic {X : Type} (R : relation X) := |
deterministic step
can be proved by induction on derivation x --> y1
generalize dependent y2
!∀ y2
by default.Ltac solve_by_inverts n
1 | Ltac solve_by_inverts n := |
think of the
-->
relation as defining an abstract machine:
execute a term
t
:
t
-->
Intutively, we call such (final state) terms values.
Okay so the point is…this language is simple enough (no stuck state).
and in this lang, value can only beC
onst:
在这个语言中,我们「规定」只有
C
onst 是「值」:
1 | Inductive value : tm → Prop := |
and we can write
ST_Plus2
more elegant:
well…in this lang, not really, since only one form of value to write out.
in cases we have multiple form of value, by doing this we don’t have to write out any cases.
value v1
t2 --> t2'
-------------------- (ST_Plus2)
P v1 t2 --> P v1 t2'
strong progress: every term either is a value or can “make progress”
1 | Theorem strong_progress : ∀t, |
terms that cannot make progress.
for an arbitrary relationR
over an arbitrary setX
normal form: term that cannot make progress (take a step)
其实我个人比较喜欢理解为「常态」或「无能量稳定态」
1 | Definition normal_form {X : Type} (R : relation X) (t : X) : Prop := |
theorem: in this language, normal forms and values are actually the same thing.
1 | Lemma value_is_nf : v, value v → normal_form step v. |
value is a syntactic concept : it is defined by looking at the form of a term
normal form is a semantic one : it is defined by looking at how the term steps.
E.g. we can defined term that can take a step as “value”:
添加一个不是 normal form 的 value
1 | Inductive value : tm → Prop := |
或者更改
step
让 value 不是 normal form…
1 | Inductive step : tm -> tm -> Prop := |
-->*
多步规约relation
multi R
: multi-step closure of R
same asclos_refl_trans_1n
inRel
chapter.
1 | Inductive multi {X : Type} (R : relation X) : relation X := |
以上是一种方便的定义,而以下则给了我们两个 helper 定理:
1 | Theorem multi_R : ∀(X : Type) (R : relation X) (x y : X), |
1 | Definition step_normal_form := normal_form step. (** 这个是一个「性质」 Property : _ -> Prop , 从 polymorphic 的 [normal_form] 以 [step] 实例化而来 **) |
something stronger is true for this language (though not for all languages)
reduction of any termt
will eventually reach a normal form (我们知道 STLC 也有这个特性)
1 | Definition normalizing {X : Type} (R : relation X) := |
To prove this, we need lemma showing some congruence of -->*
:
同余关系,不过这次是定义在 -->*
这个关系上,again,同余指的是「关系对于结构上的操作保持」
1 | Lemma multistep_congr_1 : ∀t1 t1' t2, |
Then we can prove…
1 | Theorem step_normalizing : |
1 | Theorem eval__multistep : ∀t n, |
What if we combined the lang Arith
and lang Boolean
?
Would step_deterministic
and strong_progress
still holds?
Intuition:
step_deterministic
should still holdstrong_progress
would definitely not!!test 5
or tru + 4
.progress
(which require well-typeness)1 | Theorem strong_progress : |
又到了老朋友 IMP……还好没练习……简单看一下
首先对于定义小步语义,我们需要定义 value
和 -->
(step)
aexp
, bexp
1 | Inductive aval : aexp → Prop := |
bexp
不需要 value
因为在这个语言里 BTrue
和 BFalse
的 step 总是 disjointed 得,所以并没有任何复用 value
predicate 的时候
-->a
, -->b
这里,我们先为 aexp
, bexp
定义了它们各自的小步语义,
但是,其实 from PLT we know, 我们其实也可以直接复用
aexp
,bexp
的大步语义!
- 大步语义要短得多
aexp
,bexp
其实并不会出
- 「不停机」: 没有 jump 等控制流结构
- 「异常」/「卡住」: 我们在 meta-language 的 AST 里就区分了
aexp
和bexp
,相当于主动约束了类型,所以不会出现5 || 3
这样 type error 的 AST
cmd
, -->
我们把
SKIP
当作一个「命令值(command value)」 i.e. 一个已经到达 normal form 的命令。
- 赋值命令归约到
SKIP
(和一个新的 state)。- 顺序命令等待其左侧子命令归约到
SKIP
,然后丢弃它,并继续对右侧子命令归约。
对
WHILE
命令的归约是把WHILE
命令变换为条件语句,其后紧跟同一个WHILE
命令。
这些都与 PLT 是一致的
为了展示 小步语义 的能力,let’s enrich IMP with concurrency.
It’s slightly confusing here to use Par
(meaning in parallel)
I mean, concurrency could be in parallel but it doesn’t have to…
1 | Inductive com : Type := |
啊哈!IMP 章节 Stack Machine,我们之前仅仅定义了 Fixpoint s_execute
和 Fixpoint s_compile
,这里给出其小步语义
对于本身就与「小步语义」在精神上更统一的「抽象机」,我怀疑其语义都应该是足够「小」的(即大小步将是一致的?)
1 | Definition stack := list nat. |
「编译器的正确性」= the notion of semantics preservation (in terms of observable behaviours)
S =e
C =s_compile e
B(S) =aeval st e
B(C) = functionals_execute
| relationalstack_multistep
之前我们证明过 functional/computational Fixpoint
的性质
1 | Theorem s_compile_correct : forall (st : state) (e : aexp), |
现在则是证明 relational Inductive
的性质,同样我们需要一个更一般的定理(然后原命题作为推论)
1 | Theorem stack_step_theorem : forall (st : state) (e : aexp) (stack : list nat) (prog : list sinstr), |
normalize
TacticEven with eapply
and auto
…manual normalization is tedious:
1 | Example step_example1' : |
We could write custom Tactic Notation
…(i.e. tactic macros)
1 | Tactic Notation "print_goal" := |
instantiate
seems here for intros ∃
?
1 | Example step_example1''' : exists e', |
But what surprise me is that we can eapply ex_intro
, which leave the ∃
as a hole ?ex
(unification variable).
This chapter:
type preservation
and progress
(i.e. soundness proof) – 类型保留,可进性The toy lang from SmallStep
is too “safe” to demonstrate any runtime (or dynamic) type errors. – 运行时类型错误
So that’s add some operations (common church numeral ones), and bool
type.
…same teaching order as TAPL. In PLT, we went directly to STLC.
1 | t ::= tru | fls | test t then t else t | zro | scc t | prd t | iszro t |
1 | Inductive tm : Type := |
Hint
are added to database to help with auto
.
More details on auto. eapply. eauto.
were mentioned in lf/Auto
.
1 | Hint Constructors bvalue nvalue. |
Small-step operational semantics…
can be made formally in Coq code:
1 | Reserved Notation "t1 '-->' t2" (at level 40). |
Noticed that the small-step semantics doesn’t care about if some term would eventually get stuck.
因为这个语言有 stuck 的情况,所以
value != normal form
(terms cannot make progress)possible_results_of_reduction = value | stuck
1 | Notation step_normal_form := (normal_form step). |
scc zro
is a value1 | Inductive ty : Type := |
Noticed that it’s just a non-dependently-typed ADT, but : ty
is written explcitly here…they are the same!
okay the funny thing…
it make sense to use ∈
here since :
has been used by Coq.
but this notation is actually represented as \in
.
We suddenly switch to LaTex mode…
1 | Reserved Notation "'|-' t '\in' T" (at level 40). |
Noticed the generic T
here.
In PLT we sometimes treat them as “magic” meta variable, here we need to make the T
explcit (we are in the meta-language).
⊢ t1 ∈ Bool ⊢ t2 ∈ T ⊢ t3 ∈ T
---------------------------------- (T_Test)
⊢ test t1 then t2 else t3 ∈ T
1 | | T_Test : ∀t1 t2 t3 T, (** <--- explicit ∀ T **) |
1 | Example has_type_1 : |
(Since we’ve included all the constructors of the typing relation in the hint database, the
auto
tactic can actually find this proof automatically.)
类型关系是一个保守的(或静态的)近似
1 | Example has_type_not : |
Lemma
Canonical Forms 典范形式As PLT.
1 | Theorem progress : ∀t T, |
Progress vs Strong Progress?
Progress require the “well-typeness”!
Induction on typing relation.
1 | Theorem preservation : ∀t t' T, |
按 PLT 的思路 Induction on HT,需要 inversion HE 去枚举所有情况拿到 t’ 之后证明 HT’
按 PFPL 的思路 Inudction on HE, 只需 inversion HT,因为 HT 是按 reduction 相反方向定义的!
- reduction 方向,AST top-down e.g. (+ 5 5) —–> 10
- typing 方向,AST bottom-up e.g. |- ..:N |—– |- (+ 5 5):N
1 | Proof with eauto. |
The preservation theorem is often called subject reduction, – 主语化简
想象 term 是主语,仅仅 term 在化简,而谓语宾语不变
one might wonder whether the opposity property — subject expansion — also holds. – 主语拓张
No, 我们可以很容易从(test tru zro fls)
证明出|- fls \in Nat
. – 停机问题 (undecidable)
a well-typed term never get stuck.
1 | Definition multistep := (multi step). (** <--- from SmallStep **) |
Induction on -->*
, the multi-step derivation. (i.e. the reflexive-transtive closure)
Noticed that in PLT, we explcitly write out what is “non-stuck”.
But here is ~(stuck t')
thus the proof becomes:
1 | R : step_normal_form x (** normal form **) |
The proof is weird tho.
this chapter:
“Base Types”, only Bool
for now. – 基类型
…again, exactly following TAPL.
1 | t ::= |
Some known λ-idioms:
two-arg functions are higher-order one-arg fun, i.e. curried
no named functions yet, all “anonymous” – 匿名函数
Bool
, fls
Formalize syntax.
things are, as usual, in the Type
level, so we can “check” them w/ dependent type.
1 | Inductive ty : Type := |
Noted that,
\x:T.t
(formally,abs x T t
), the argument type is explicitly annotated (not inferred.)
另外,这里介绍了一个小 trick: 用 Notation
(更接近 宏 ) 而非 Defintion
使得我们可以使用 auto
…
1 | (** idB = \x:Bool. x **) |
tru
and fls
are values\x:T. t
is value iff t
value. – Coq \x:T. t
is always value – most FP lang, either CBV or CBNCoq 这么做挺奇怪的,不过对 Coq 来说:
terms can be considered equiv up to the computation VM (在其项化简可以做到的范围内都算相等)
this rich the notion of Coq’s value (所以 Coq 的值的概念是比一般要大的)
Three ways to construct value
(unary relation = predicate)
1 | Inductive value : tm → Prop := |
Having made the choice not to reduce under abstractions, we don’t need to worry about whether variables are values, since we’ll always be reducing programs “from the outside in,” and that means the step relation will always be working with closed terms.
if we could reduce under abstraction and variables are values… What’s the implication here? 始终不懂…
[x:=s]t
and pronounced “substitute s for x in t.”
(\x:Bool. test x then tru else x) fls ==> test fls then tru else fls
Important capture example:
[x:=tru] (\x:Bool. x) ==> \x:Bool. x -- x is bound, we need α-conversion here
!=> \x:Bool. tru
Informal definition…
[x:=s]x = s
[x:=s]y = y if x ≠ y
[x:=s](\x:T11. t12) = \x:T11. t12
[x:=s](\y:T11. t12) = \y:T11. [x:=s]t12 if x ≠ y
[x:=s](t1 t2) = ([x:=s]t1) ([x:=s]t2)
...
and formally:
1 | Reserved Notation "'[' x ':=' s ']' t" (at level 20). |
Computable
Fixpoint
means meta-function! (in metalanguage, Coq here)
Is if x ≠ y
for function abstraction one sufficient? – 在 PLT 中我们采取了更严格的定义
Only safe if we only consider
s
is closed term.
Prof.Mtf:
here…it’s not really “defining on closed terms”. Technically, you can still write open terms.
if we want, we could define the realclosed_term
…more works to prove things tho.
Prof.Mtf:
In some more rigorous setting…we might define
well_typed_term
and the definition itself is the proof ofPreservation
!
Should be familar
value v2
---------------------------- (ST_AppAbs) until value, i.e. function (β-reduction)
(\x:T.t12) v2 --> [x:=v2]t12
t1 --> t1'
---------------- (ST_App1) reduce lhs, Function side
t1 t2 --> t1' t2
value v1
t2 --> t2'
---------------- (ST_App2) reduce rhs, Arg side
v1 t2 --> v1 t2'
Formally,
(I was expecting they invents some new syntax for this one…so we only have AST)
1 | Reserved Notation "t1 '-->' t2" (at level 40). |
idBB idB -> idB
idBB (idBB idB) -> idB
idBB (notB tru) -> idBB fls ....
idB fls
we need something like environment but for Types.
three-place typing judgment, informally written – 三元类型断言
Gamma ⊢ t ∈ T
“under the assumptions in Gamma, the term t has the type T.”
1 | Definition context := partial_map ty. |
Why partial_map
here?
IMP can use total_map
because it gave default value for undefined var.
Gamma x = T
---------------- (T_Var) look up
Gamma |- x \in T
(x |-> T11 ; Gamma) |- t12 \in T12
---------------------------------- (T_Abs) type check against context w/ arg
Gamma |- \x:T11.t12 \in T11->T12
Gamma |- t1 \in T11->T12
Gamma |- t2 \in T11
---------------------- (T_App)
Gamma |- t1 t2 \in T12
1 | Example typing_example_1 : |
example_2
eapply
A
?? looks like need need another environment to look up A
…decidable type system = decide term if typable or not.
done by type checker…
can we prove…?
∀ Γ e, ∃ τ, (Γ ⊢ e : τ) ∨ ¬(Γ ⊢ e : τ)
– a type inference algorithm!
Provability in Coq witness decidabile operations.
Keep inversion till the contradiction.
基本的定理依赖关系 top-down:
Type Safety
对于我们只有 bool
一个 base type 的 STLC,只需要 bool
和 λ
:
1 | Lemma canonical_forms_bool : ∀t, |
1 | Theorem progress : ∀t T, |
类似 Types
章节的 progress
和 PLT 中的 proof.
这两个思路的证明基本一致,
auto
上来就用把 tru
, fls
, abs
三个 value
的 case 干掉了,t'
, 这时候 Canonical Form 就派上用场了preservation theorem
ST_AppAbs
比较麻烦,需要做 substitution,所以我们需要证明 substituion 本身是 type-preserving…在 PLT/TAPL 中,我们将 “free variables of an term” 定义为一个集合 FV(t)
. (集合是一种 computational 的概念)
FV(x) = {x}
FV(λx.t1) = FV(t1) ∪ FV(t2)
FV(t1 t2) = FV(t1) \ {x}
在这里,我们则将 “appears_free in” 定义为 var x
与 term t
上的二元关系: (读作 judgement 即可)
1 | Inductive appears_free_in : string → tm → Prop := |
An open term is one that may contain free variables.
“Open” precisely means “possibly containing free variables.”
the closed terms are a subset of the open ones.
closed 是 open 的子集…这样定义吗(
首先我们需要一个「free var 都是 well-typed 」的 lemma
1 | Lemma free_in_context : ∀x t T Gamma, (** 名字有一点 misleading,意思是 "free vars is in context" 而不是 "var is free in context"... **) |
由此我们可以推论 所有在 empty context 下 well typed 的 term 都是 closed 得:
1 | Corollary typable_empty__closed : ∀t T, |
PLT 的 Weaking 和 Exchanging 其实就对应了 Gamma 作为 partial_map
的 neq
和 permute
这里,我们直接进一步地证明 「term 的 well-typeness 在『free var 的值不变的 context 变化下』是 preserving 得」:
1 | Lemma context_invariance : ∀Gamma Gamma' t T, |
1 | Lemma substitution_preserves_typing : ∀Gamma x U t v T, |
可以被看做一种交换律 (“commutation property”)
即先 type check 再 substitution 和 先 substition 再 type check 是等价的
Proof by induction on term 不好证,挺麻烦的
1 | Theorem preservation : ∀t t' T, |
1 | Theorem not_subject_expansion: |
(app (abs x (Arrow Bool Bool) tru) tru) -- 考虑 term
(λx:Bool->Bool . tru) tru --> tru -- 可以 step
empty |- Bool -- step 后 well-typed
empty |-/- (λx:Bool->Bool . tru) tru -- 但是原 term 显然 ill-typed
1 | (** stuck 即在不是 value 的时候无法 step **) |
这里的 Uniqueness 与 Right-unique / deterministic / functional 其实都是相同的内涵
1 | Theorem unique_types : ∀Gamma e T T', |
only
Nat
…这样就不用管 the interaction betweenBool
andNat
1 | Inductive ty : Type := |
更多拓展见下一章 MoreStlc.v
make the STLC into a PL!
其实这一部分我好像没有任何必要做笔记……
See StlcProp.v
exercise stlc_arith
.
let x = t1 in e
as a derived form of (λx . e) t1
.let x:T = t1 in e
as a derived form of (λx:T . e) t1
. (both require explicit type annotation)SF here, same as TaPL, treat it less derived by _compute the type T1
from t1
.
λ
later on, here we directly “execute” it via substituion.我想这里有一个原因是, λ
必须要可以独立被 typed,但是这时候我们还没有 t1
,无法计算出 T1
。而 let
的形式中包括了 t1
,所以可以直接计算:
1 | t ::= Terms |
Reduction:
t1 --> t1'
---------------------------------- (ST_Let1)
let x=t1 in t2 --> let x=t1' in t2
---------------------------- (ST_LetValue) <-- substitute as λ
let x=v1 in t2 --> [x:=v1]t2
Typing:
Gamma |- t1 \in T1 x|->T1; Gamma |- t2 \in T2
-------------------------------------------------- (T_Let)
Gamma |- let x=t1 in t2 \in T2
1 | t ::= Terms |
Reduction:
t1 --> t1'
-------------------- (ST_Pair1)
(t1,t2) --> (t1',t2)
t2 --> t2'
-------------------- (ST_Pair2)
(v1,t2) --> (v1,t2')
t1 --> t1'
------------------ (ST_Fst1)
t1.fst --> t1'.fst
------------------ (ST_FstPair)
(v1,v2).fst --> v1
t1 --> t1'
------------------ (ST_Snd1)
t1.snd --> t1'.snd
------------------ (ST_SndPair)
(v1,v2).snd --> v2
Typing:
Gamma |- t1 \in T1 Gamma |- t2 \in T2
----------------------------------------- (T_Pair)
Gamma |- (t1,t2) \in T1*T2
Gamma |- t \in T1*T2
--------------------- (T_Fst)
Gamma |- t.fst \in T1
Gamma |- t \in T1*T2
--------------------- (T_Snd)
Gamma |- t.snd \in T2
unit
is the only value/normal form of type Unit
, but not the only term (also any terms that would reduce to unit
)
1 | t ::= Terms |
No reduction rule!
Typing:
---------------------- (T_Unit)
Gamma |- unit \in Unit
wouldn’t every computation living in such a type be trivial?
难道不是每个计算都不会在这样的类型中_居留_吗?
Where Unit really comes in handy is in richer languages with side effects
在更丰富的语言中,使用 Unit 类型来处理副作用(side effect) 会很方便
deal with values that can take two distinct forms – binary sum type
两个截然不同的 … “二元和”类型
We create elements of these types by tagging elements of the component types
我们在创建这些类型的值时,会为值_标记_上其”成分”类型
标签 inl
, inr
可以看做为函数,即 Data Constructor
inl : Nat -> Nat + Bool
inr : Bool -> Nat + Bool
that “inject” (注入) elements of
Nat
orBool
into the left and right components of the sum typeNat+Bool
不过这里并没有把他们作为 function 来形式化,而是把 inl
inr
作为关键字,把 inl t
inr t
作为 primitive syntactic form…
L (e)
and say the T2
would be “guessed” to produce T1 + T2
, as TaPL option 1L [T1 +T2] (e)
i.e. provide a explicit type annotation for the sum type, as TaPL option 3 (ascription)SF here, use something in the middle:
T2
to L(t1)
and T1
would be computed from t1
to form the T1 + T2
.1 | t ::= Terms |
Reduction:
t1 --> t1'
------------------------ (ST_Inl)
inl T2 t1 --> inl T2 t1'
t2 --> t2'
------------------------ (ST_Inr)
inr T1 t2 --> inr T1 t2'
t0 --> t0'
------------------------------------------- (ST_Case)
case t0 of inl x1 => t1 | inr x2 => t2 -->
case t0' of inl x1 => t1 | inr x2 => t2
----------------------------------------------- (ST_CaseInl)
case (inl T2 v1) of inl x1 => t1 | inr x2 => t2
--> [x1:=v1]t1
----------------------------------------------- (ST_CaseInr)
case (inr T1 v2) of inl x1 => t1 | inr x2 => t2
--> [x2:=v1]t2
Typing:
Gamma |- t1 \in T1
------------------------------ (T_Inl)
Gamma |- inl T2 t1 \in T1 + T2
Gamma |- t2 \in T2
------------------------------- (T_Inr)
Gamma |- inr T1 t2 \in T1 + T2
Gamma |- t \in T1+T2
x1|->T1; Gamma |- t1 \in T
x2|->T2; Gamma |- t2 \in T
---------------------------------------------------- (T_Case)
Gamma |- case t of inl x1 => t1 | inr x2 => t2 \in T
The typing features we have seen can be classified into
- 基本类型 base types like
Bool
, and- 类型构造子 type constructors like
→
and*
that build new types from old ones.
In principle, we could encode lists using pairs, sums and recursive types. (and type operator to give the type a name in SystemFω)
但是 recursive type 太 non-trivial 了……于是我们直接处理为一个特殊的类型吧
in PLT slide, again, we omit the type and simply write nil : List T
hd nil
这样 stuck 的可能,所以额外给了一个用 unlist
(unempty list) 的 defin PLT langF, we did use pairs + sums + recursive types:
nil : all('a . rec('b . unit + ('a * 'b)))
nil : ∀α . µβ . unit + (α ∗ β)
in TaPL ch11, we manually provide T
to all term (data constructor)
nil
need it! (others can be inferred by argument)and that’s we did for SF here!
1 | t ::= Terms |
Reduction:
t1 --> t1'
-------------------------- (ST_Cons1)
cons t1 t2 --> cons t1' t2
t2 --> t2'
-------------------------- (ST_Cons2)
cons v1 t2 --> cons v1 t2'
t1 --> t1'
------------------------------------------- (ST_Lcase1)
(lcase t1 of nil => t2 | xh::xt => t3) -->
(lcase t1' of nil => t2 | xh::xt => t3)
----------------------------------------- (ST_LcaseNil)
(lcase nil T of nil => t2 | xh::xt => t3)
--> t2
------------------------------------------------ (ST_LcaseCons)
(lcase (cons vh vt) of nil => t2 | xh::xt => t3)
--> [xh:=vh,xt:=vt]t3 -- multiple substi
Typing:
------------------------- (T_Nil)
Gamma |- nil T \in List T
Gamma |- t1 \in T Gamma |- t2 \in List T
--------------------------------------------- (T_Cons)
Gamma |- cons t1 t2 \in List T
Gamma |- t1 \in List T1
Gamma |- t2 \in T
(h|->T1; t|->List T1; Gamma) |- t3 \in T
--------------------------------------------------- (T_Lcase)
Gamma |- (lcase t1 of nil => t2 | h::t => t3) \in T
通用的递归,而非 primitive recursion (PFPL)
1 | fact = \x:Nat . if x=0 then 1 else x * (fact (pred x))) |
这个在 Stlc 中不被允许,因为我们在定义 fact
的过程中发现了一个 free 的 fact
,要么未定义,要么不是自己。
所以我们需要 Fixpoint
1 | fact = fix (\fact:Nat->Nat. |
1 | t ::= Terms |
Reduction:
t1 --> t1'
------------------ (ST_Fix1)
fix t1 --> fix t1'
-------------------------------------------- (ST_FixAbs)
fix (\xf:T1.t2) --> [xf:=fix (\xf:T1.t2)] t2 -- fix f = f (fix f)
Typing:
Gamma |- t1 \in T1->T1
---------------------- (T_Fix)
Gamma |- fix t1 \in T1
这里的定义非常 informal:
1 | t ::= Terms |
Reduction:
ti --> ti'
------------------------------------ (ST_Rcd)
{i1=v1, ..., im=vm, in=ti , ...}
--> {i1=v1, ..., im=vm, in=ti', ...}
t1 --> t1'
-------------- (ST_Proj1)
t1.i --> t1'.i
------------------------- (ST_ProjRcd)
{..., i=vi, ...}.i --> vi
Typing:
Gamma |- t1 \in T1 ... Gamma |- tn \in Tn
---------------------------------------------------- (T_Rcd)
Gamma |- {i1=t1, ..., in=tn} \in {i1:T1, ..., in:Tn}
Gamma |- t \in {..., i:Ti, ...}
------------------------------- (T_Proj)
Gamma |- t.i \in Ti
提了一嘴
μ
加起来就可以
give us enough mechanism to build arbitrary inductive data types like lists and trees from scratch
Basically
ADT = Unit + Product + Sum (Variant) + Function (Expo)
但是 Coq 的 Inductive
还需要进一步的 Pi (Dependent Product), Sigma (Dependent Sum).
基本上就是把上面的 rule 用 AST 写进来
a bit of Coq hackery to automate searching for typing derivation
基本上就是自动化的 pattern matching + tactics
1 | Hint Extern 2 (has_type _ (app _ _) _) => |
效果非常酷:typecheck 只需要 eauto
,reduction 只需要 normalize
.
Record Subtyping…
row type
index? record impl as list
width/depth/permulation
Java
having both width/permulation subtyping make impl slow
ML has depth?
OCaml objection has all three
Looking at Contravariant!
(2) {i1:S,i2:T}→U <: {i1:S,i2:T,i3:V}→U
(4) {i1:T,i2:V,i3:V} <: {i1:S,i2:U} * {i3:V}
is interesting:
the interesting thing is, why don’t we make some subtyping rules for that as well?
3 and 4. (5) …
A <: Top => Top -> A <: A -> A – contravariant
if we only care (A*T)
, can use T:Top
but to type the whole thing : A
Top -> A
?
but noticed that we said \z:A.z
can we pass A -> A
into Top -> A
?
more specific more general
smallest -> most specific -> A -> A
largest -> most specific -> Top -> A
5.
“The type Bool has no proper subtypes.” (I.e., the only type smaller than Bool is Bool itself.)
Ture unless we have Bottom
hmm seems like Bottom
in subtyping is different with Empty/Void, which is closer to logical Bottom ⊥
since Bottom here is subtyping of everything..
OH they are the same: (nice)
inversion
doesn’t lose information, induction
does.
auto rememeber?? — dependent induction
hetergeous equaltiy
In soundness proof
Lemma: If Gamma ⊢ \x:S1.t2 ∈ T, then there is a type S2 such that x⊢>S1; Gamma ⊢ t2 ∈ S2 and S1 → S2 <: T.
why T
not arrow? Top…
if including Bottom…many proof becomes hard, canonical form need to say…might be Bottom?
no, no value has type Bottom (Void)…