Commit c24814e9 by REMY Didier

merge

parents 12d27e9b 054e4511
# Functional programming and type systems (2017-2018)
[The official MPRI
page](https://wikimpri.dptinfo.ens-cachan.fr/doku.php?id=cours:c-2-4-2)
This page supplements
[the official page of MPRI 2-4](https://wikimpri.dptinfo.ens-cachan.fr/doku.php?id=cours:c-2-4-2).
## Location
## Location and duration
The lessons take place at University of Paris 7 - Denis Diderot,
Batiment Sophie Germain in room 2035 on Fridays at 12:45 and ends at 15:30.
There will be a break of 15' in the middle of the course.
The lectures take place at University Paris 7 - Denis Diderot,
Bâtiment Sophie Germain, in room 2035.
They are scheduled on Fridays from 12:45 to 15:30.
There is a 15-minute break in the middle of each lecture.
## Teachers
......@@ -20,6 +22,7 @@ There will be a break of 15' in the middle of the course.
This course presents the principles and formalisms that underlie many of
today's typed functional programming languages.
(Here are some [introductory slides](slides/fpottier-00.pdf).)
The course is made up of four parts and can be split after the first two
parts.
......@@ -43,8 +46,8 @@ systems. We study parametric polymorphism (as in System F and ML), data
types and type abstraction. We show syntactic type soundness (via progress
and subject reduction) by reasoning by induction on typing derivations. We
also show how to obtain semantic properties via logical relations by
reasoning by induction on the structure of types. We also introduce
subtyping and row polymorphism and illustrate typing problems induced by
reasoning by induction on the structure of types. Finally, we introduce
subtyping, row polymorphism, and illustrate the problems induced by
side effects (references) and the need for the value restriction.
The third part of the course describes more advanced features of type
......@@ -61,25 +64,50 @@ We also show the limits of dependently-typed functional programming.
### Functional Programming: Under the Hood
* (22/09/2017) From a small-step operational semantics...
* (29/09/2017) ... to an efficient interpreter. (2 weeks.)
* (06/10/2017) Compiling away first-class functions: closure conversion, defunctionalization.
* (13/10/2017) Compiling away the call stack: the CPS transformation.
* (20/10/2017) Equational reasoning and program optimizations.
* (22/09/2017)
Introduction ([slides 00](slides/fpottier-00.pdf)).
Syntax and operational semantics, on paper and on a machine
([slides 01a](slides/fpottier-01a.pdf))
([slides 01b](slides/fpottier-01b.pdf)).
* Newton-Raphson in OCaml ([solution](ocaml/NewtonRaphson.ml)).
* 1 is not even in Coq ([Even.v](coq/Even.v)).
* (29/09/2017)
From a small-step semantics down to an efficient verified interpreter,
in several stages
([Coq demo](coq/DemoSyntaxReduction.v))
([slides 02](slides/fpottier-02.pdf))
([OCaml code](ocaml/Lambda.ml))
([Coq repo](coq/)).
* (06/10/2017) Compiling away first-class functions:
closure conversion, defunctionalization
([slides 03](slides/fpottier-03.pdf))
([Coq repo](coq/)).
* (13/10/2017) Making the stack explicit: the CPS transformation
([slides 04](slides/fpottier-04.pdf))
([Coq repo](coq/)).
* Transforming a call-by-value interpreter
([exercise](ocaml/EvalCBVExercise.ml), [solution](ocaml/EvalCBVCPS.ml)).
* Transforming a call-by-name interpreter
([solution](ocaml/EvalCBNCPS.ml)).
* Transforming a graph traversal
([solution](ocaml/Graph.ml)).
* (20/10/2017) Equational reasoning and program optimizations
([slides 05](slides/fpottier-05.pdf))
([Coq mini-demo](coq/DemoEqReasoning.v)).
### Metatheory of Typed Programming Languages
* (15/09/2017)
[Metatheory of System F](http://gallium.inria.fr/~remy/mpri/slides1.pdf)
(See also [intro](http://gallium.inria.fr/~remy/mpri/slides8.pdf),
and chap [1](http://gallium.inria.fr/~remy/mpri/cours1.pdf)
and [2](http://gallium.inria.fr/~remy/mpri/cours2.pdf)
(See also [intro](http://gallium.inria.fr/~remy/mpri/slides8.pdf),
and chap [1](http://gallium.inria.fr/~remy/mpri/cours1.pdf)
and [2](http://gallium.inria.fr/~remy/mpri/cours2.pdf)
of [course notes](http://gallium.inria.fr/~remy/mpri/cours.pdf))
* (27/10/2017)
[ADTs, existential types, GADTs]
(http://gallium.inria.fr/~remy/mpri/slides2.pdf).
* (03/11/2017) Logical relations.
* (10/11/2017) Subtyping. Rows.
* (10/11/2017) Subtyping. Rows.
* (17/11/2017) References, Value restriction, Side effects.
### Advanced Aspects of Type Systems
......@@ -108,24 +136,24 @@ who split the course.
Although the course has changed, you may still have a look at previous exams
available with solutions:
- mid-term exam 2016-2017:
- mid-term exam 2016-2017:
[Record concatenation](http://gallium.inria.fr/~remy/mpri/exams/partiel-2016-2017.pdf)
- mid-term exam 2015-2016:
- mid-term exam 2015-2016:
[Type containment](http://gallium.inria.fr/~remy/mpri/exams/partiel-2015-2016.pdf)
- final exam 2014-2015: [Copatterns](http://gallium.inria.fr/~remy/mpri/exams/final-2014-2015.pdf)
- mid-term exam 2014-2015:
- mid-term exam 2014-2015:
[Information flow](http://gallium.inria.fr/~remy/mpri/exams/partiel-2014-2015.pdf)
- final exam 2013-2014:
- final exam 2013-2014:
[Operation on records](http://gallium.inria.fr/~remy/mpri/exams/final-2013-2014.pdf)
- mid-term exam 2013-2014:
- mid-term exam 2013-2014:
[Typechecking Effects](http://gallium.inria.fr/~remy/mpri/exams/partiel-2013-2014.pdf)
- final exam 2012-2013:
- final exam 2012-2013:
[Refinement types](http://gallium.inria.fr/~remy/mpri/exams/final-2012-2013.pdf)
- mid-term exam 2012-2013:
- mid-term exam 2012-2013:
[Variations on ML](http://gallium.inria.fr/~remy/mpri/exams/partiel-2012-2013.pdf)
- final exam 2011-2012:
- final exam 2011-2012:
[Intersection types](http://gallium.inria.fr/~remy/mpri/exams/final-2011-2012.pdf)
- mid-term exam 2011-2012:
- mid-term exam 2011-2012:
[Parametricity](http://gallium.inria.fr/~remy/mpri/exams/partiel-2011-2012.pdf)
- final exam 2010-2011:
[Compiling a language with subtyping](http://gallium.inria.fr/~xleroy/mpri/2-4/exam-2010-2011.pdf)
......@@ -135,19 +163,58 @@ available with solutions:
## Recommended software
OCaml 4.0x and Coq **8.5**.
Please install [opam](https://opam.ocaml.org/doc/Install.html) first.
Once you have installed [opam](https://opam.ocaml.org/doc/Install.html), use the following commands:
Then, install OCaml 4.0x and Coq **8.5** via the following commands:
```bash
opam init --comp=4.05 # for instance
opam repo add coq-released https://coq.inria.fr/opam/released
opam update
opam install -j4 -v coq.8.5.3
```
(Do *not* install Coq 8.6. The version of AutoSubst that I am using is
not compatible with it. If for some reason you need Coq 8.6, or have
already installed Coq 8.6, note that `opam switch` can be used to let
multiple versions of Coq coexist.)
Please also install François Pottier's
[variant](https://github.com/fpottier/autosubst)
of the
[AutoSubst](https://www.ps.uni-saarland.de/autosubst/) library:
```bash
git clone git@github.com:fpottier/autosubst.git
make -C autosubst install
```
In order to use Coq inside `emacs`,
[ProofGeneral](https://proofgeneral.github.io/)
is highly recommended.
Here is a suggested installation script:
```bash
rm -rf /tmp/PG
cd /tmp
git clone git@github.com:ProofGeneral/PG.git
cd PG
EMACS=/Applications/Aquamacs.app/Contents/MacOS/Aquamacs
if [ ! -x $EMACS ]; then
EMACS=emacs
fi
make EMACS=$EMACS compile
TARGET=/usr/local/share/emacs/site-lisp/ProofGeneral
sudo rm -rf $TARGET
sudo mv /tmp/PG $TARGET
```
Enable ProofGeneral by adding the following line to your `.emacs` file:
```elisp
(load-file "/usr/local/share/emacs/site-lisp/ProofGeneral/generic/proof-site.el")
```
If desired, ProofGeneral can be further
[customized](https://proofgeneral.github.io/doc/userman/ProofGeneral_9/).
## Bibliography
[Types and Programming Languages](https://mitpress.mit.edu/books/types-and-programming-languages),
[Types and Programming Languages](https://mitpress.mit.edu/books/types-and-programming-languages),
Benjamin C. Pierce, MIT Press, 2002.
[Advanced Topics in Types and Programming Languages](https://www.cis.upenn.edu/~bcpierce/attapl/),
......
*.vo
*.glob
*.v.d
.*.aux
.coq-native
_CoqProject
*~
Require Import Omega.
Require Import Autosubst.Autosubst.
Require Import MyTactics. (* TEMPORARY *)
(* -------------------------------------------------------------------------- *)
(* A more recognizable notation for lifting. *)
Notation lift i t := (t.[ren(+i)]).
(* -------------------------------------------------------------------------- *)
Section Extras.
Context A `{Ids A, Rename A, Subst A, SubstLemmas A}.
Lemma up_ren:
forall xi,
ren (upren xi) = up (ren xi).
Proof.
intros. autosubst.
Qed.
Lemma upn_ren:
forall i xi,
ren (iterate upren i xi) = upn i (ren xi).
Proof.
induction i; intros.
{ reflexivity. }
{ rewrite <- fold_up_upn. rewrite <- IHi. asimpl. reflexivity. }
Qed.
Lemma plus_upn: (* close to [up_liftn] *)
forall i sigma,
(+i) >>> upn i sigma = sigma >> ren (+i).
Proof.
induction i; intros.
{ rewrite iterate_0. autosubst. }
{ rewrite iterate_S. asimpl. rewrite IHi. autosubst. }
Qed.
Lemma up_sigma_up_ren:
forall t i sigma,
t.[up sigma].[up (ren (+i))] = t.[up (ren (+i))].[upn (1 + i) sigma].
Proof.
intros. asimpl. rewrite plus_upn. asimpl. reflexivity.
Qed.
Lemma upn_k_sigma_x:
forall k sigma x,
x < k ->
upn k sigma x = ids x.
Proof.
induction k; intros; asimpl.
{ omega. }
{ destruct x; asimpl.
{ eauto. }
{ rewrite IHk by omega. autosubst. }
}
Qed.
Lemma push_substitution_last:
forall t v i,
t.[v .: ren (+i)] = t.[up (ren (+i))].[v/].
Proof.
intros. autosubst.
Qed.
Lemma push_substitution_last_up_hoist:
forall t v i j,
t.[up (v .: ren (+i))].[up (ren (+j))] =
t.[up (up (ren (+j + i)))].[up (lift j v .: ids)].
Proof.
intros. autosubst.
Qed.
Lemma lift_lift:
forall i j t,
lift i (lift j t) = lift (i + j) t.
Proof.
intros. autosubst.
Qed.
Lemma lift_upn:
forall t i sigma,
(lift i t).[upn i sigma] = lift i t.[sigma].
Proof.
intros. asimpl.
erewrite plus_upn.
reflexivity.
Qed.
Lemma lift_up:
forall t sigma,
(lift 1 t).[up sigma] = lift 1 t.[sigma].
Proof.
intros. change up with (upn 1). eapply lift_upn.
Qed.
Lemma up_sigma_f:
forall (sigma : var -> A) (f : A -> A),
f (ids 0) = ids 0 ->
(forall i t, lift i (f t) = f (lift i t)) ->
up (sigma >>> f) = up sigma >>> f.
Proof.
intros. f_ext. intros [|x]; asimpl; eauto.
Qed.
Lemma upn_sigma_f:
forall (sigma : var -> A) (f : A -> A),
f (ids 0) = ids 0 ->
(forall i t, lift i (f t) = f (lift i t)) ->
forall i,
upn i (sigma >>> f) = upn i sigma >>> f.
Proof.
induction i; intros.
{ reflexivity. }
{ do 2 rewrite <- fold_up_upn. rewrite IHi. erewrite up_sigma_f by eauto. reflexivity. }
Qed.
Lemma upn_theta_sigma_ids:
forall theta sigma i,
theta >> sigma = ids ->
upn i theta >> upn i sigma = ids.
Proof.
intros theta sigma i Hid.
rewrite up_comp_n.
rewrite Hid.
rewrite up_id_n.
reflexivity.
Qed.
Lemma up_theta_sigma_ids:
forall theta sigma,
theta >> sigma = ids ->
up theta >> up sigma = ids.
Proof.
change up with (upn 1). eauto using upn_theta_sigma_ids.
Qed.
Lemma scons_scomp:
forall (T : A) Gamma theta,
T.[theta] .: (Gamma >> theta) = (T .: Gamma) >> theta.
Proof.
intros. autosubst.
Qed.
(* BUG: the two sides of this equation are distinct, yet they are
printed identically. *)
Goal
forall v f,
v .: (ids >>> f) = (v .: ids) >>> f.
Proof.
intros.
Fail reflexivity.
Abort.
End Extras.
(* This incantation means that [eauto with autosubst] can use the tactic
[autosubst] to prove an equality. *)
Hint Extern 1 (_ = _) => autosubst : autosubst.
(* This incantation means that [eauto with autosubst] can use the lemmas
whose names are listed here. This is useful when an equality involves
metavariables, so the tactic [autosubst] fails. *)
Hint Resolve scons_scomp : autosubst.
(* -------------------------------------------------------------------------- *)
Require Import List.
Require Import MyTactics. (* TEMPORARY *)
Require Import Autosubst.Autosubst.
Require Import Autosubst_EOS. (* [eos_var] *)
(* Environments are sometimes represented as finite lists. This file
provides a few notions that helps deal with this representation. *)
Section Env.
Context {A} `{Ids A, Rename A, Subst A, SubstLemmas A}.
(* -------------------------------------------------------------------------- *)
(* The function [env2subst default], where [default] is a default value,
converts an environment (a finite list) to a substitution (a total
function). *)
Definition env2subst (default : A) (e : list A) (x : var) : A :=
nth x e default.
(* -------------------------------------------------------------------------- *)
(* [env_ren_comp e xi e'] means (roughly) that the environment [e] is equal to
the composition of the renaming [xi] and the environment [e'], that is,
[e = xi >>> e']. We also explicitly require the environments [e] and [e']
to have matching lengths, up to [xi], as this is *not* a consequence of
the other premise. *)
Inductive env_ren_comp : list A -> (var -> var) -> list A -> Prop :=
| EnvRenComp:
forall e xi e',
(forall x, x < length e -> xi x < length e') ->
(forall x default, nth x e default = nth (xi x) e' default) ->
env_ren_comp e xi e'.
(* A reformulation of the second premise in the above definition. *)
Lemma env_ren_comp_eq:
forall e xi e',
(forall default, env2subst default e = xi >>> env2subst default e') <->
(forall x default, nth x e default = nth (xi x) e' default).
Proof.
unfold env2subst. split; intros h; intros.
{ change (nth x e default) with ((fun x => nth x e default) x).
rewrite h. reflexivity. }
{ f_ext; intro x. eauto. }
Qed.
(* -------------------------------------------------------------------------- *)
(* Initialization: [e = id >>> e]. *)
Lemma env_ren_comp_id:
forall e,
env_ren_comp e (fun x => x) e.
Proof.
econstructor; eauto.
Qed.
(* -------------------------------------------------------------------------- *)
(* The relation [e = xi >>> e'] can be taken under a binder, as follows. *)
Lemma env_ren_comp_up:
forall e xi e' v,
env_ren_comp e xi e' ->
env_ren_comp (v :: e) (upren xi) (v :: e').
Proof.
inversion 1; intros; subst; econstructor;
intros [|x]; intros; simpl in *; eauto with omega.
Qed.
(* -------------------------------------------------------------------------- *)
(* One element can be prepended to [e'], provided [xi] is adjusted. *)
Lemma env_ren_comp_prepend:
forall e xi e' v,
env_ren_comp e xi e' ->
env_ren_comp e (xi >>> (+1)) (v :: e').
Proof.
inversion 1; intros; subst.
econstructor; intros; simpl; eauto with omega.
Qed.
(* -------------------------------------------------------------------------- *)
(* A consequence of [env_ren_comp_id] and [env_ren_comp_prepend]. The renaming
(+1) will eat away the first entry in [v :: e]. *)
Lemma env_ren_comp_plus1:
forall e v,
env_ren_comp e (+1) (v :: e).
Proof.
econstructor; intros; simpl; eauto with omega.
Qed.
(* -------------------------------------------------------------------------- *)
(* More generally, the renaming [eos_var x], which means that [x] goes out of
scope, will eat away the entry at index [x] in [e1 ++ v :: e2]. *)
Lemma env_ren_comp_eos_var:
forall x e1 v e2,
x = length e1 ->
env_ren_comp (e1 ++ e2) (eos_var x) (e1 ++ v :: e2).
Proof.
rewrite eos_var_eq_lift_var. unfold lift_var.
econstructor; intros y; dblib_by_cases.
{ rewrite app_length in *. simpl. omega. }
{ rewrite app_length in *. simpl. omega. }
{ do 2 (rewrite app_nth2 by omega).
replace (1 + y - length e1) with (1 + (y - length e1)) by omega.
reflexivity. }
{ do 2 (rewrite app_nth1 by omega).
reflexivity. }
Qed.
(* -------------------------------------------------------------------------- *)
End Env.
Hint Resolve
env_ren_comp_id
env_ren_comp_up
env_ren_comp_prepend
env_ren_comp_plus1
env_ren_comp_eos_var
: env_ren_comp.
Require Import Omega.
Require Import Autosubst.Autosubst.
Require Import AutosubstExtra.
Require Import Autosubst_EOS.
(* -------------------------------------------------------------------------- *)
Class IdsLemmas (term : Type) {Ids_term : Ids term} := {
(* The identity substitution is injective. *)
ids_inj:
forall x y,
ids x = ids y ->
x = y
}.
(* -------------------------------------------------------------------------- *)
Section FreeVars.
Context
{A : Type}
{Ids_A : Ids A}
{Rename_A : Rename A}
{Subst_A : Subst A}
{IdsLemmas_A : IdsLemmas A}
{SubstLemmas_A : SubstLemmas A}.
(* -------------------------------------------------------------------------- *)
(* A reformulation of [ids_inj]. *)
Lemma ids_inj_False:
forall x y,
ids x = ids y ->
x <> y ->
False.
Proof.
intros.
assert (x = y). { eauto using ids_inj. }
unfold var in *.
omega.
Qed.
(* -------------------------------------------------------------------------- *)
(* The predicate [fv k t] means that the free variables of the term [t] are
contained in the semi-open interval [0..k). *)
Definition fv k t :=
t.[upn k (ren (+1))] = t.
(* -------------------------------------------------------------------------- *)
(* The predicate [closed t] means that the term [t] is closed, that is, [t]
has no free variables. *)
Definition closed :=
fv 0.
(* -------------------------------------------------------------------------- *)
(* This technical lemma states that the renaming [+1] is injective. *)
Lemma lift_inj_ids:
forall t x,
t.[ren (+1)] = ids (S x) <-> t = ids x.
Proof.
split; intros.
{ eapply lift_inj. autosubst. }
{ subst. autosubst. }
Qed.
(* -------------------------------------------------------------------------- *)
(* This lemma characterizes the meaning of [fv k] when applied to a variable. *)
Lemma fv_ids_eq:
forall k x,
fv k (ids x) <-> x < k.
Proof.
unfold fv. induction k; intros.
(* Base case. *)
{ asimpl. split; intros; elimtype False.
{ eauto using ids_inj_False. }
{ omega. }
}
(* Step. *)
{ destruct x; asimpl.
{ split; intros. { omega. } { reflexivity. } }
{ rewrite lift_inj_ids.
rewrite <- id_subst.
rewrite IHk. omega. }
}
Qed.
(* -------------------------------------------------------------------------- *)
(* A simplification lemma. *)
Lemma fv_lift:
forall k i t,
fv (k + i) t.[ren (+i)] <-> fv k t.
Proof.
unfold fv. intros. asimpl.
rewrite Nat.add_comm.
rewrite <- upn_upn.
erewrite plus_upn by eauto.
rewrite <- subst_comp.
split; intros.
{ eauto using lift_injn. }
{ f_equal. eauto. }
Qed.
(* -------------------------------------------------------------------------- *)
(* If [t] has at most [n - 1] free variables,
and if [x] is inserted among them,
then we get [eos x t],
which has at most [n] free variables. *)
Lemma fv_eos:
forall x n t,
x < n ->
fv (n - 1) t ->
fv n (eos x t).
Proof.
unfold fv. intros x n t ? ht.
rewrite eos_eq in ht.
rewrite eos_eq.
rewrite eos_eos_reversed by omega. (* nice! *)
rewrite ht.
reflexivity.
Qed.
Lemma fv_eos_eq:
forall x n t,
x < n ->
fv n (eos x t) <->
fv (n - 1) t.
Proof.
unfold fv. intros x n t ?.
rewrite eos_eq.
rewrite eos_eq.
rewrite eos_eos_reversed by omega. (* nice! *)
split; intros h.
{ eauto using eos_injective. }
{ rewrite h. reflexivity. }
Qed.
(* -------------------------------------------------------------------------- *)
(* A substitution [sigma] is regular if and only if, for some [j], for
sufficiently large [x], [sigma x] is [x + j]. *)
Definition regular (sigma : var -> A) :=
exists i j,
ren (+i) >> sigma = ren (+j).
Lemma regular_ids:
regular ids.
Proof.
exists 0. exists 0. autosubst.
Qed.
Lemma regular_plus:
forall i,
regular (ren (+i)).
Proof.
intros. exists 0. exists i. autosubst.
Qed.
Lemma regular_upn:
forall n sigma,
regular sigma ->
regular (upn n sigma).
Proof.
intros ? ? (i&j&hsigma).
exists (n + i). eexists (n + j).
replace (ren (+(n + i))) with (ren (+i) >> ren (+n)) by autosubst.
rewrite <- scompA.
rewrite up_liftn.
rewrite scompA.
rewrite hsigma.
autosubst.
Qed.
(* -------------------------------------------------------------------------- *)
(* If the free variables of the term [t] are below [k], then [t] is unaffected
by a substitution of the form [upn k sigma]. *)
(* Unfortunately, in this file, where the definition of type [A] is unknown, I
am unable to establish this result for arbitrary substitutions [sigma]. I
am able to establish it for *regular* substitutions, where The proof is somewhat interesting, so it is given here, even
though, once the definition of the type [A] is known, a more direct proof,
without a regularity hypothesis, can usually be given. *)
(* An intermediate result states that, since [upn k (ren (+1))] does not