Skip to content
Snippets Groups Projects
Commit 4328487e authored by Max New's avatar Max New
Browse files

Hello, synthetic world!

parents
Branches
No related tags found
No related merge requests found
*.aux
*.log
/gtlc.pdf
*.agdai
open import Relation.Binary.PropositionalEquality using (_≡_)
open import Data.Product
postulate
▸ : Set → Set
K : Set
𝕌 : Set₁
𝕌 = Set
ℙ : Set₁
ℙ = Set
record Preorder : Set₁ where
field
X : 𝕌
_⊑_ : X → X → ℙ
refl : ∀ (x : X) → x ⊑ x
trans : ∀ {x y z : X} → x ⊑ y → y ⊑ z → x ⊑ z
infixr 20 _⇨_
infixr 20 _⇒_
record _⇨_ (X : Preorder) (Y : Preorder) : Set where
module X = Preorder X
module Y = Preorder Y
field
f : X.X → Y.X
mon : ∀ {x y} → X._⊑_ x y → Y._⊑_ (f x) (f y)
app : ∀ {X Y} → (X ⇨ Y) → Preorder.X X → Preorder.X Y
app = _⇨_.f
_$_ = app
_⇒_ : Preorder → Preorder → Preorder
X ⇒ Y = record { X = X ⇨ Y
; _⊑_ = λ f g → (x : X.X) → _⇨_.f f x ⊑y _⇨_.f g x
; refl = λ x x₁ → _⇨_.mon x (X.refl x₁)
; trans = λ p1 p2 x → Y.trans (p1 x) (p2 x) }
where
module X = Preorder X
module Y = Preorder Y
_⊑y_ = Y._⊑_
_⊨_⊑_ : (X : Preorder) → Preorder.X X → Preorder.X X → Set
X ⊨ x ⊑ x' = Preorder._⊑_ X x x'
record _⊨_≣_ (X : Preorder) (x y : Preorder.X X) : Set where
module X = Preorder X
_⊑_ = X._⊑_
field
to : x ⊑ y
fro : y ⊑ x
record _⇔_ (X : Preorder) (Y : Preorder) : Set where
field
to : X ⇨ Y
fro : Y ⇨ X
eqX : ∀ x → X ⊨ app fro (app to x) ≣ x
eqY : ∀ y → Y ⊨ app to (app fro y) ≣ y
record _◃_ (X Y : Preorder) : Set where
_⊑y_ = Preorder._⊑_ Y
field
emb : X ⇨ Y
prj : Y ⇨ X
projection : ∀ y → Y ⊨ app emb (app prj y) ⊑ y
retraction : ∀ x → X ⊨ x ≣ app prj (app emb x)
op : Preorder → Preorder
op X = record
{ X = X.X
; _⊑_ = λ x y → y X.⊑ x
; refl = X.refl
; trans = λ p1 p2 → X.trans p2 p1
}
where module X = Preorder X
opF : ∀ {X Y} → (X ⇨ Y) → op X ⇨ op Y
opF {X}{Y} f = record { f = f.f ; mon = _⇨_.mon f }
where module X = Preorder X
module Y = Preorder Y
module f = _⇨_ f
product : Preorder → Preorder → Preorder
product X Y = record { X = X.X × Y.X
; _⊑_ = λ p1 p2 → (proj₁ p1 ⊑x proj₁ p2) × (proj₂ p1 ⊑y proj₂ p2)
; refl = λ x → (X.refl (proj₁ x)) , (Y.refl (proj₂ x))
; trans = λ leq1 leq2 → (X.trans (proj₁ leq1) (proj₁ leq2)) , Y.trans (proj₂ leq1) (proj₂ leq2)
}
where module X = Preorder X
_⊑x_ = X._⊑_
module Y = Preorder Y
_⊑y_ = Y._⊑_
record FiberPts {X : Preorder}{Y : Preorder} (f : X ⇨ Y) (y : Preorder.X Y) : Set where
field
pt : Preorder.X X
over : _⇨_.f f pt ≡ y
Fiber : {X : Preorder}{Y : Preorder} (f : X ⇨ Y) (y : Preorder.X Y) → Preorder
Fiber {X}{Y} f y = record { X = FiberPts f y
; _⊑_ = λ x x' → FiberPts.pt x ⊑x FiberPts.pt x'
; refl = λ x → X.refl (FiberPts.pt x)
; trans = λ p1 p2 → X.trans p1 p2 }
where module X = Preorder X
_⊑x_ = X._⊑_
module Y = Preorder Y
record fibration {X : Preorder} {Y : Preorder} (f : X ⇨ Y) : Set where
module X = Preorder X
module Y = Preorder Y
_⊑x_ = X._⊑_
_⊑y_ = Y._⊑_
module f = _⇨_ f
field
-- A < B -> tm B -> tm A (downcast)
pull : ∀ (x : X.X) {y : Y.X} → (y ⊑y app f x) → X.X
-- the downcast is a lower bound
-- dncast (A < B) N <= N
pullLB : ∀ {x : X.X} {y : Y.X} → (c : y ⊑y app f x) → pull x c ⊑x x
-- the downcast is the *greatest* lower bound over a type at least as low
-- Given N : B
-- and M' : A' where A' <= A <= B
-- and M' <= N over A' <= A <= B
-- then M' <= dncast (A <= B) N over A' <= A
pullGLB : ∀ {x : X.X} {y : Y.X} {x' : X.X} → (c : y ⊑y app f x) → (app f x' ⊑y y) → (x' ⊑x x) → x' ⊑x pull x c
opfibration : ∀ {X Y} (f : X ⇨ Y) → Set
opfibration f = fibration (opF f)
record GLTC : Set₁ where
field
type : Preorder
module type = Preorder type
_⊑ty_ = type._⊑_
field
term : Preorder
type-of : term ⇨ type
dncasts : fibration type-of
upcasts : opfibration type-of
-- need that the dncast of an upcast is the identity(!)
-- projection : {!!}
module term = Preorder term
module type-of = _⇨_ type-of
_⊑tm_ = term._⊑_
-- dynamic type
field
dyn : type.X
dynT : ∀ A → A ⊑ty dyn
of-ty : type.X → Preorder
of-ty A = Fiber type-of A
-- errors
field
err : ∀ A → Preorder.X (of-ty A)
-- err⊥ : ∀ M →
-- can we define err to be the least element of type dyn which then is then
-- err <= up (M) so dn(err) <= dn(up(M))
-- function types
field
arr : type ⇨ type ⇒ type
arr' : type.X → type.X → type.X
arr' A B = app (app arr A) B
field
lam : ∀ {A B} → (of-ty A ⇒ of-ty B) ⇔ of-ty (arr' A B)
-- can we *prove* that application preserves error, i.e., that (err{A -> B} N = err{B})?
-- doubtful... seems like we need to add it in as an axiom, i.e., that the above is an iso of *pointed* preorders
-- boolean types
field
bool : type.X
-- this doesn't satisfy the UMP because
-- there are terms that are not strict in their input (x |- x)
if : ∀ {A} → product (of-ty A) (of-ty A) ◃ (of-ty bool ⇒ of-ty A)
-- -- terms are more interesting because they are "clocked"
-- term : type → K → Set
-- _||_⊨_⊑₁_ : ∀ {A B : type} → (A ⊑₀ B) → (k : K) → term A k → term B k → ℙ
-- -- reflexivity is "approximation-wise"
-- refl₁ : ∀ {A}{M : ∀ k → term A k} → (k : K) → refl₀ || k ⊨ (M k) ⊑₁ (M k)
-- -- transitivity is only "in the limit"
-- trans₁ : ∀ {A B C}{M : ∀ k → term A k}{N : ∀ k → term B k}{P : ∀ k → term C k}
-- {AB : A ⊑₀ B}{BC : B ⊑₀ C}
-- → (∀ k → AB || k ⊨ (M k) ⊑₁ (N k))
-- → (∀ k → BC || k ⊨ (N k) ⊑₁ (P k))
-- → ∀ k → trans₀ AB BC || k ⊨ (M k) ⊑₁ (P k)
-- -- the above defines a kind of "guarded functor" ty : term -> type
-- -- upcasts/downcasts ask that that functor be an/a opfibration/fibration
-- up : ∀ {A B} → A ⊑₀ B → ∀ k → term A k → term B k
-- dn : ∀ {A B} → A ⊑₀ B → ∀ k → term B k → term A k
-- postulate
-- ▸₁ : Set₁ → Set₁
-- fix : (▸₁ 𝕌 → 𝕌) → 𝕌
-- θ𝕌 : ▸₁ 𝕌 → 𝕌
-- infixl 30 _+_
-- data _+_ (A B : Set) : Set where
-- inl_ : A → A + B
-- inr_ : B → A + B
-- record One : Set where
-- constructor ⟨⟩
-- Two : Set
-- Two = One + One
-- L℧ : Set → Set
-- L℧ X = fix (λ L℧X → One + X + θ𝕌 L℧X)
-- dyn℧ : Set
-- dyn℧ = fix λ dyn℧ → L℧ ((Two + (θ𝕌 dyn℧ → θ𝕌 dyn℧)))
record GTLC-CBV : Set₁ where
field
type : Preorder
valu : Preorder
comp : Preorder
ty-ofv : valu ⇨ type
ty-ofc : comp ⇨ type
module type = Preorder type
val-of-ty : type.X → Preorder
val-of-ty A = Fiber ty-ofv A
comp-of-ty : type.X → Preorder
comp-of-ty A = Fiber ty-ofc A
field
-- not quite right, need the rhs to be some kind of strict morphisms.
-- should probably have a third sort of ev ctxts from A to B
lett : ∀ {A B} → (val-of-ty A ⇒ comp-of-ty B) ⇔ (comp-of-ty A ⇒ comp-of-ty B)
upcasts : opfibration ty-ofv
dncasts : fibration ty-ofc -- problem this doesn't imply that downcasts are linear, maybe we add this as a separate prop?
-- something for projection property
-- dynamic type
dyn : type.X
dyn⊤ : ∀ A → type ⊨ A ⊑ dyn
-- errors...
-- functions
arr : type ⇨ type ⇒ type
arr' : type.X → type.X → type.X
arr' A B = app (app arr A) B
field
lam : ∀ {A B} → (val-of-ty A ⇒ comp-of-ty B) ⇔ val-of-ty (arr' A B)
-- bools
bool : type.X
if : ∀ {A} → product (comp-of-ty A) (comp-of-ty A) ⇔ (val-of-ty bool ⇒ comp-of-ty A)
gtlc.tex 0 → 100644
\documentclass{article}
\usepackage{amssymb}
\usepackage{amsmath}
\usepackage{amsthm}
\usepackage{tikz-cd}
\usepackage{mathpartir}
\usepackage{stmaryrd}
\newtheorem{theorem}{Theorem}[section]
\newtheorem{nonnum-theorem}{Theorem}[section]
\newtheorem{corollary}{Corollary}[section]
\newtheorem{definition}{Definition}[section]
\newtheorem{lemma}{Lemma}[section]
\newcommand{\dyn}{\text{Dyn}}
\newcommand{\dynv}{\text{Dyn}^+}
\newcommand{\dync}{\text{Dyn}^-}
\newcommand{\good}[1]{\text{good}_{#1}}
\newcommand{\prop}{\mathbb P}
\newcommand{\with}{\mathrel{\&}}
\newcommand{\eqv}{\simeq}
\newcommand{\soln}{\text{Sol}}
\newcommand{\police}[1]{\text{police}_{#1}}
\newcommand{\later}{{\blacktriangleright}}
\newcommand{\errp}[1]{\mho_{#1}}
\newcommand{\kerrp}[2]{\mho^{#1}_{#2}}
\newcommand{\err}{\mho}
\newcommand{\errlift}{L_\err}
\newcommand{\ostar}{\circledast}
\newcommand{\ltdynp}[1]{\mathrel{\sqsubseteq_{#1}}}
\newcommand{\ltdynlift}[1]{\mathrel{\sqsubseteq_{\errlift#1}}}
\newcommand{\ltprecp}[1]{\mathrel{\sqsubseteq^{\prec}_{\errlift #1}}}
\newcommand{\ltsuccp}[1]{\mathrel{\sqsubseteq^{\succ}_{#1}}}
\newcommand{\kltp}[2]{\mathrel{\sqsubseteq^{#1}_{#2}}}
\newcommand{\ltgt}[1]{\mathbin{\langle\mspace{-1mu}#1\mspace{-1mu}\rangle}}
\newcommand{\fmap}{\ltgt{\$}}
\newcommand{\monto}{\mathrel{\to_{m}}}
\newcommand{\linto}{\multimap}
\begin{document}
\title{Semantics of Gradual Types in SGDT}
\author{Max S. New}
\maketitle
\section{Goals}
We want to define a denotational semantics for the core language of
GTLC and prove graduality.
Here's roughly the structure required
\begin{verbatim}
record GTLC(U)
type : U
tm : type -> U
_<ty=_ : PreOrder type
_<tm=_ : PreOrder (Sigma A (tm A))
impl : (A, M) <tm= (B,N) -> A <ty= B
dyn : type
dynTop : {A} -> A <ty= dyn
ans : type
yes : tm ans
no : tm ans
arr : type -> type -> type
lam : (tm A -> tm B) -> tm (arr A B)
app : tm (arr A B) -> tm A -> tm B
-- beta, eta
up : A <ty= B -> tm A -> tm B
upR : ...
dn : A <ty= B -> tm B -> tm A
\end{verbatim}
\section{Error predomains and domains}
First, we need to define our monad.
\begin{definition}
Define the error-lift type as a solution to the guarded recursive
domain equation:
\[ \errlift X \cong (X + 1 + \later \errlift X) \]
We label the three injections as follows:
\begin{align*}
\eta &: X \to \errlift X\\
\err &: \errlift X\\
\theta &: \later \errlift X \to \errlift X
\end{align*}
This carries the structure of a strong monad, with $\eta$ as the
unit and the join defined by L\"ob induction as follows:
\begin{align*}
\mu(\eta x) &= x\\
\mu(\mho) &= \mho\\
\mu(\theta(u)) &= \theta (\mu^\later \ostar u)
\end{align*}
With map (implying strength) defined as
\begin{align*}
\errlift f(\eta x) &= f x\\
\errlift f(\mho) &= \mho\\
\errlift f(\theta(u)) &= \theta ((\errlift f)^\later \ostar u)
\end{align*}
And the equational laws of a monad can be proven using L\"ob
induction.
\end{definition}
This can be seen as simply a composition of two monads using a
distributive law: the error monad and the recursive lift monad.
%
However, we present them as one combined monad because in gradual
typing we are interested in a specific ordering relation called the
\emph{error ordering} where $\err$ is the least element. This is
\emph{not} the composition of the lift and error monad, which would
instead have the error as an isolated, maximal element.
We can define this error ordering as a variation on the weak
simulation relations of prior work:
\begin{definition}
Let $X$ be a type and $\sqsubseteq_X$ a binary relation. We define
$\ltdynp{\errlift X} : \errlift X \to \errlift X \to \prop$ as follows:
\begin{align*}
\err \ltdynlift X d &= \top\\
\eta x \ltdynlift X \eta y &= x \ltdynp X y\\
\eta x \ltdynlift X \err &= \bot\\
\eta x \ltdynlift X \theta t &= \exists{n:\mathbb N}.\exists{y: X}. \theta t = \delta^n (\eta y) \wedge x \ltdynp X y\\
\theta s \ltdynlift X \eta y &= \exists{n:\mathbb N}.(\theta s = \delta^n \err)\vee(\exists{y: X}. \theta t = \delta^n (\eta y) \wedge x \ltdynp X y)\\
\theta s \ltdynlift X \err &= \exists{n:\mathbb N}.\theta s = \delta^n \err\\
\theta s \ltdynlift X \theta t &= \later[l \leftarrow s,r\leftarrow t] s \ltdynlift X t
\end{align*}
\end{definition}
\begin{lemma}
When $\ltdynp X$ is reflexive, so is $\ltdynlift X$.
\end{lemma}
\begin{proof}
By L\"ob induction on the proposition $\forall d: \errlift X. d
\ltdynlift X d$. Error and return cases are immediate. We need to
show
\[ \theta t \ltdynlift X \theta t = \later[l \leftarrow t,r\leftarrow t] l \ltdynlift X r = \later[l \leftarrow t] l \ltdynlift X l \]
The inductive hypothesis $h : \later (\forall d: \errlift X. d \ltdynlift X d)$
We can then conclude
\[ \text{next}[f \leftarrow h, l \leftarrow t]. h l \]
\end{proof}
Unfortunately, transitivity is not preserved.
%
The problematic case is of the form $\theta s \ltdynlift X \theta t
\ltdynlift X \eta z$. In this case we know $\theta t = \delta^n (\eta
y)$ but we cannot conclude that $\theta s$ must eventually terminate!
In fact this is false in the semantics because it might be that
$\theta s$ is only related to $\theta t$ because we ran out of fuel,
and actually $s$ is a diverging computation.
However, this should support transitive reasoning \emph{in the limit},
i.e., if the equivalence holds for \emph{all} levels of approximation
then eventually if $\theta t$ terminates, at high enough level of
approximation it will no longer be related to the diverging
computation.
%
This reasoning \emph{in the limit} is accomplished analytically by
quantification over all steps.
%
Here we accomplish it by using \emph{clocks} and \emph{clock
quantification}.
%
That is rather than a denotation of a syntactic type being a type it
will be given by a ``clocked'' type:
\begin{definition}
A \emph{clocked} type $X$ is an element of $K \to U$.
We call $\forall k:K. X k$, the \emph{limit} of $X$.
\end{definition}
Note that, similar to the interval in cubical type theory, $K$ is not
a type, but only a ``pseudo-type'' that we can quantify over in the
type $\Pi_{k:K} B$.
%
Next, we need a ``clocked'' error ordering associated to every type.
%
This will be assumed to be reflexive at each level of approximation,
but only transitive in the limit.
\begin{definition}
A \emph{clocked} preorder on a clocked type $X : K \to U$ is a
clocked relation $\kltp {} X : \forall k. X_k \to X_k \to \prop$ satisfying
\begin{enumerate}
\item Clocked Reflexivity $\forall k. \prod_{x:X_k} x \kltp k X x$
\item Transitivity in the limit $\prod_{x,y,z:\forall k. X_k} x \kltp \omega X y \to y \kltp \omega X z \to x \kltp \omega X z$
\end{enumerate}
Where
\[ x \kltp \omega X y = \forall k. x_k \kltp k X y_k \]
A \emph{monotone function} is a function $f : \forall k. X_0 k \to
Y_0 k$ satisfying monotonicity:
\[ \forall k.\prod_{x,x':X_0^k} x \kltp k X x' \to f_k x \kltp k Y f_k x' \]
\end{definition}
For any clocked preorder we can construct the delayed preorder by
\begin{definition}
Define $\later : K \to (K \to U) \to (K \to U)$ by
\[ (\later X)^k = \later^k X^k \]
and on preorders by:
\begin{align*}
x \kltp k {\later X} y &= \later^k[l\leftarrow x, r\leftarrow y].~l \kltp k {X} r
\end{align*}
\end{definition}
Then we can define our semantic notions
\begin{definition}
An \emph{error predomain} $X$ consists of
\begin{enumerate}
\item A clocked type $X_0$
\item A clocked preorder $\kltp {} X$ on $X_0$
\end{enumerate}
A morphism of error predomains is a monotone function.
An \emph{error domain} is an error predomain $X$ with
\begin{enumerate}
\item A least element $\kerrp {} X : \forall k. X$, i.e., it
satisfies $\forall k. \prod_{x:X_k} \kerrp k X \kltp k X x$.
\item A monotone ``thunk'' function $\theta_X : \later X \to X$
\end{enumerate}
A morphism of error domains is a morphism of the underlying error
predomains.
A \emph{linear} morphism of error domains $S : X \multimap Y$ is a
morphism of error domains additionally satisfying
\begin{enumerate}
\item Error preservation $S^k \err^k_X = \err^k_Y$
\item Thunk preservation $S^k (\theta^k_X x) = \theta^k_Y (S^k \fmap x)$
\end{enumerate}
\end{definition}
Finally we can return to our original goal of defining the monad for our semantics!
%
\begin{lemma}
next and $\delta$ are monotone
\end{lemma}
\begin{definition}
Let $X$ be an error predomain a binary relation. We define the error
domain $\errlift X$ as
TODO: put the ks in the right spots
\begin{enumerate}
\item $(\errlift X)_0^k = \mu L. X_0^k + 1 + \later^k L$
\item Ordering defined by cases:
\begin{align*}
\err \kltp k {\errlift X} d &= \top\\
\eta x \kltp k {\errlift X} \eta y &= x \ltdynp X y\\
\eta x \kltp k {\errlift X} \err &= \bot\\
\eta x \kltp k {\errlift X} \theta t &= \exists{n:\mathbb N}.\exists{y: X}. \theta t = \delta^n (\eta y) \wedge x \ltdynp X y\\
\theta s \kltp k {\errlift X} \eta y &= \exists{n:\mathbb N}.(\theta s = \delta^n \err)\vee(\exists{y: X}. \theta t = \delta^n (\eta y) \wedge x \ltdynp X y)\\
\theta s \kltp k {\errlift X} \err &= \exists{n:\mathbb N}.\theta s = \delta^n \err\\
\theta s \kltp k {\errlift X} \theta t &= \later[l \leftarrow s,r\leftarrow t] s \kltp k {\errlift X} t
\end{align*}
\item reflexive: as above
\item TODO: transitive in the limit
\item TODO: strong monad
\end{enumerate}
\end{definition}
\begin{lemma}
$\errlift X$ is the free error domain on $X$, i.e., it is left
adjoint to the forgetful functor from the category of error domains
and linear maps to the category of predomains.
\end{lemma}
\begin{lemma}
The adjunction is monadic: error domains are precisely algebras of
the free error domain. Is this true?
\end{lemma}
\section{Lazy Semantics}
To define a semantics for lazy gradually typed language, we first need
to define our \emph{universal} error domain. Unless we add in features
like pattern matching on the dynamic type, there is some freedom in
this choice. We present two natural solutions:
The first is a classic-looking dynamic type: the lift of the sum of
the base type and the function type. A notable difference are the
guarded recursive uses.
\[ \dyn_+ \cong \errlift (2 + (\later \dyn_+ \monto \later \dyn_+)) \]
The second is slightly closer to untyped lambda calculus: we take a
product rather than a sum, and only need to lift the base type itself.
\[ \dyn_- \cong \errlift 2 \times (\later \dyn_- \monto \later \dyn_-) \]
The idea here is that any dynamically typed term can be safely applied
to any number of arguments and at some point ``projected'' to return a
boolean, which will actually cause computation to occur as indicated
by the $\errlift$.
To construct these domains we need to be able to solve recursive
domain equations \emph{of error domains}. To do this we simply need to
show that the universe of error predomains is a predomain.
\begin{definition}
Define $\theta_{\predom} : \later \predom \to \predom$ as follows
\begin{align*}
\theta_{\predom}P &= (\later[(X,\ltdynp X) \leftarrow P] X, )
\end{align*}
\end{definition}
\end{document}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment