Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
S
sgdt
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Package registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
gradual-typing
sgdt
Commits
4aa877cd
Commit
4aa877cd
authored
6 years ago
by
Max New
Browse files
Options
Downloads
Patches
Plain Diff
some notes on doing threesomes with cbpv
parent
57613974
No related branches found
No related tags found
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
notes/impl.tex
+221
-0
221 additions, 0 deletions
notes/impl.tex
with
221 additions
and
0 deletions
notes/impl.tex
0 → 100644
+
221
−
0
View file @
4aa877cd
\documentclass
{
article
}
\usepackage
{
float
}
\usepackage
{
amsmath,amssymb, amsthm
}
\usepackage
{
tikz-cd
}
\usepackage
{
mathpartir
}
\usepackage
{
rotating
}
\usepackage
{
stmaryrd
}
\newtheorem
{
lemma
}{
Lemma
}
\renewcommand
{
\u
}{
\underline
}
\newcommand
{
\kw
}
[1]
{
\texttt
{
#1
}
\,\,
}
\newcommand
{
\sem
}
[1]
{
\llbracket
#1
\rrbracket
}
\newcommand
{
\dynv
}{{
?
}}
\newcommand
{
\dync
}{
\u
{
\text
{
?`
}}}
\newcommand
{
\ltdyn
}{
\sqsubseteq
}
\newcommand
{
\gtdyn
}{
\sqsupseteq
}
\newcommand
{
\equidyn
}{
\mathrel
{
\gtdyn\ltdyn
}}
\newcommand
{
\dynmeet
}{
\sqcap
}
\newcommand
{
\uarrow
}{
\mathrel
{
\rotatebox
[origin=c]
{
-30
}{$
\leftarrowtail
$}}}
\newcommand
{
\darrow
}{
\mathrel
{
\rotatebox
[origin=c]
{
30
}{$
\twoheadleftarrow
$}}}
\newcommand
{
\upcast
}
[2]
{
\langle
{
#2
}
\uarrow
{
#1
}
\rangle
}
\newcommand
{
\dncast
}
[2]
{
\langle
{
#1
}
\darrow
{
#2
}
\rangle
}
\newcommand
{
\case
}{
\kw
{
case
}}
\newcommand
{
\pipe
}{
\,
|
\,
}
\newcommand
{
\caseofXthenYelseZ
}
[3]
{
\case
#1
\{
#2
\pipe
#3
\}
}
\newcommand
{
\bindXtoYinZ
}
[2]
{
\kw
{
bind
}
#2
\leftarrow
#1;
}
\newcommand
{
\ret
}{
\kw
{
ret
}}
\newcommand
{
\err
}{
\mho
}
\newcommand
{
\thunk
}
[1]
{
\{
#1
\}
}
\newcommand
{
\force
}{
!
}
\begin{document}
\title
{
Zig-zag Casts in Gradual Type Theory
}
\author
{
Max S. New
}
\section
{
Reflecting on Type Dynamism
}
We translate GTT into a CBPV language extended with a pair of
connectives that model.
%
These come in two forms: the delayed upcast of a thunk
$
(
U
)
$
, and the
delayed downcast of a returner
$
(
\u
F
)
$
.
%
In the contract translation, these cases are ``problematic''.
%
The upcast of a
$
U
$
type introduces a proxy, for instance the cast
$
\upcast
{
U
(
2
\to
\u
B
)
}{
U
(
\dynv
\to
\u
B
)
}$
is implemented as:
\[
\sem
{
\upcast
{
U
(
2
\to
\u
B
)
}{
U
(
\dynv
\to
\u
B
)
}
V
}
\cong
\thunk
{
(
\lambda
(
x:
\dynv
)
.
\bindXtoYinZ
{
\dncast
{
\u
F
2
}{
\u
F
\dynv
}
x
}
{
(
x':
2
)
}
\force
V
\,
x'
)
}
\]
%
which adds an indirection to the actual implementation.
%
In general, one indirection seems unavoidable, but worse is that a
sequence of upcasts of the same thunk will result in a linear number
of indirections.
%
Dually, the downcast of a
$
\u
F
$
type is a
\emph
{
non-tail
}
call, for
instance the cast
$
\dncast
{
\u
F
2
}{
\u
F
\dynv
}$
is, in the natural and
Scheme-like interpretations, implemented as a case-analysis:
\[
\sem
{
\dncast
{
\u
F
2
}{
\u
F
\dynv
}
M
}
\cong
\bindXtoYinZ
M x
\caseofXthenYelseZ
x
{
\texttt
{
in
}_
2
x
_
2
.
\ret
x
_
2
}{
\texttt
{
else
}
.
\err
}
\]
if
$
M
$
is a tail call, then this downcast breaks the tail call,
because we need
$
M
$
to return to the cast, which then performs the
case-analysis and returns.
%
Adding one return indirection like this seems unavoidable, but worse
is that a sequence of downcasts of
$
\u
F
$
types results in a linear
number of indirections.
Essentially these are the same/dual problems, and we solve them with
the same/dual solution.
%
The basic idea is to consider the
$
U
$
type of GTT
\emph
{
not
}
to be a
type of thunks, but
\emph
{
delayed casts of thunks
}
.
%
That is, a value of type
$
U
\u
B
$
in GTT is not necessarily
represented by a
$
U
\u
B
$
at runtime, but rather some original type
$
\u
B
_
i
$
(i for implementation) that has been casted to
$
U
\u
B
$
,
\emph
{
via
}
some type
$
\u
B
_
m
$
(m for middle).
%
This is a ``threesome cast'' (which I will refer to as a zig-zag cast
because it is more descriptive: we cast down and then up), the use of
a middle type allows us to ``summarize'' a sequence of casts into a
single pair of casts.
%
Thus in general the cast through the middle type will be
\emph
{
stronger
}
than the direct cast: otherwise we wouldn't need the
middle type at all.
%
We can represent this as a
\emph
{
dependent pair
}
:
\[
\sem
{
U
\u
B
}
=
\sum
_{
\u
Y
\ltdyn
\u
B
}
\sum
_{
\u
Y'
\gtdyn
\u
Y
}
U
\u
Y'
\]
%
Then a thunk is implemented by instantiating
$
\u
Y
$
with
$
\u
B
$
(using
reflexivity):
\[
\sem
{{
\thunk
M
}_{
\u
B
}}
=
(
\u
B
\ltdyn
\u
B,
\u
B
\gtdyn
\u
B,
\thunk
M
)
\]
Forcing a proxied thunk is implemented by running the implementation
of the zig zag of casts (which can be interpreted on the fly or a jump
to a predetermined implementation):
\[
\sem
{
\force
}
(
\u
Y
\ltdyn
\u
B,
\u
Y'
\gtdyn
\u
Y, V : U
\u
Y'
)
=
\force
\sem
{
\upcast
{
U
\u
Y
}{
U
\u
B
}}
\thunk
{
\sem
{
\dncast
{
\u
Y
}{
\u
Y'
}}
\force
V
}
\]
Finally, we compose with casts.
%
An upcast of a thunk is trivial: just replace
$
B
$
with
$
B'
$
.
%
\[
\sem
{
\upcast
{
U B
}{
U B'
}}
(
Y
\ltdyn
B, Y'
\gtdyn
Y, V
)
=
(
Y
\ltdyn
B', Y'
\gtdyn
Y, V
)
\]
A downcast of a thunk does the real computation: we replace the middle
type
$
Y
$
with the
\emph
{
meet
}
of
$
Y
$
:
\[
\sem
{
\dncast
{
U B
}{
U B'
}
(
Y
\ltdyn
B', Y'
\gtdyn
Y, V
)
}
=
(
Y
\dynmeet
B
\ltdyn
B, Y'
\gtdyn
Y
\dynmeet
B, V
)
\]
Dually, for
$
\u
F
$
types, we want the
\emph
{
stacks
}
out of a
$
\u
F
$
type to be delayed casts.
%
We translate a
$
\u
F A
$
term to a term that will perform a zig-zag
cast when told which one to do, or in other words it expects the
\emph
{
stack
}
to provide it a zig-zag.
%
We can represent this as a
\emph
{
dependent function
}
:
\[
\sem
{
\u
F A
}
=
\prod
_{
X
\ltdyn
A
}
\prod
_{
X'
\gtdyn
X
}
\u
F X'
\]
A bind out of
$
\u
F A
$
is implemented by instantiating
$
X
$
with
$
A
$
itself, using reflexivity of dynamism:
\[
\sem
{
\bindXtoYinZ
{
M :
\u
F A
}
{
x
}
{
N
}}
=
\bindXtoYinZ
{
M
\,
(
A
\ltdyn
A
)
\,
(
A
\ltdyn
A
)
}
x N
\]
Return is implemented by running the zigzag cast on the stack:
\[
\sem
{
\ret
{}}
(
V : A
)
=
\lambda
(
X
\ltdyn
A
)
\lambda
(
X'
\gtdyn
X
)
.
\bindXtoYinZ
{
\sem
{
\dncast
{
\u
F X
}{
\u
F A
}}
\ret
V
}
x
\upcast
{
X
}{
X'
}
x
\]
The downcast is trivial, using transitivity of dynamism.
\[
\sem
{
\dncast
{
\u
F A
}{
\u
F A'
}}
[
M
]
\,
(
X
\ltdyn
A
)
\,
(
X'
\gtdyn
X
)
=
M
\,
(
X
\ltdyn
A
\ltdyn
A'
)
\,
(
X'
\gtdyn
X
)
\]
The upcast does the work, computing the meet:
\[
\sem
{
\upcast
{
\u
F A
}{
\u
F A'
}}
[
M
]
\,
(
X
\ltdyn
A'
)
\,
(
X'
\gtdyn
X
)
=
M
\,
(
X
\dynmeet
A
\ltdyn
A
)
\,
(
X'
\gtdyn
X
\gtdyn
X
\dynmeet
A
)
\]
We can model cast
\emph
{
failure
}
by adding rules that
$
0
,
\top
$
are
least value and computation types respectively.
%% \begin{figure}
%% \begin{mathpar}
%% \begin{array}{lcl}
%% A & \bnfdef & X \mid \mu X.A \mid U \u B \mid 0 \mid A_1 + A_2 \mid 1 \mid A_1 \times A_2 \\
%% \u B & ::= & \u Y\mid \nu \u Y. \u B \mid \u F A \mid \top \mid \u B_1 \with \u B_2 \mid A \to \u B\\
%% \Gamma & ::= & \cdot \mid \Gamma, x : A \\
%% \Delta & ::= & \cdot \mid \bullet : \u B \\
%% V & ::= & x \mid \rollty{\mu X.A}V \mid \inl{V} \mid \inr{V} \mid \\
%% & & () \mid (V_1,V_2)\mid \thunk{M}
%% \\
%% M & ::= & \err_{\u B} \mid \letXbeYinZ V x M \mid \pmmuXtoYinZ V x M \mid \rollty{\nu \u Y.\u B} M \mid \unroll M \mid \abort{V} \mid \\
%% & & \caseofXthenYelseZ V {x_1. M_1}{x_2.M_2} \mid \pmpairWtoinZ V M \mid \pmpairWtoXYinZ V x y M
%% \mid \force{V} \mid \\
%% & & \ret{V} \mid \bindXtoYinZ{M}{x}{N} \mid \lambda x:A.M \mid M\,V \mid \emptypair \mid \pair{M_1}{M_2} \mid \pi M \mid \pi' M
%% \\
%% S & ::= & \bullet \mid \bindXtoYinZ S x M \mid S\, V \mid \pi S \mid \pi' S
%% \end{array}
%% \end{mathpar}
%% \caption{Operational GTT Syntax}
%% \end{figure}
\section
{
Correctness
}
We can show the correctness of this translation by showing that it
\emph
{
simulates
}
the inefficient semantics.
That is for any GTT type
$
T
$
we can implement total ``wrapper''
functions
$
T
\Rightarrow
\sem
T
$
and
$
\sem
T
\Rightarrow
T
$
with the
property that for every term
$
\Gamma\pipe\Delta
\vdash
E : T
$
implemented in GTT,
$
E
$
is equivalent to composing
$
\sem\Gamma\pipe\sem\Delta
\vdash
\sem
E :
\sem
T
$
with the wrappers.
To prove this, the main lemma would be to prove
\begin{lemma}
[Correctness of Zigging through Meets]
{
~
}
\begin{enumerate}
\item
For every zig-zag-zig
$
A
_
2
'
\gtdyn
A
_
2
\ltdyn
A
_
1
'
\gtdyn
A
_
1
$
the cast sequence
\[
\upcast
{
\u
F A
_
2
}{
\u
F A
_
2
'
}
\dncast
{
\u
F A
_
2
}{
\u
F A
_
1
'
}
\upcast
{
\u
F A
_
1
}{
\u
F A
_
1
'
}
\]
is equivalent (
$
\equidyn
$
) to the single zig-zag:
\[
\upcast
{
\u
F
(
A
_
2
\dynmeet
A
_
1
)
}{
\u
F A
_
2
'
}
\dncast
{
\u
F
(
A
_
2
\dynmeet
A
_
1
)
}{
\u
F A
_
1
}
\]
\item
For every
$
B
_
1
\ltdyn
B
_
1
'
\gtdyn
B
_
2
\ltdyn
B
_
2
'
$
the cast sequence
\[
\dncast
{
UB
_
1
}{
UB
_
1
'
}
\upcast
{
UB
_
2
}{
UB
_
1
'
}
\dncast
{
UB
_
2
}{
UB
_
2
'
}
\]
is equivalent to the single zig-zag:
\[
\upcast
{
U
(
B
_
1
\dynmeet
B
_
2
)
}{
UB
_
1
}
\dncast
{
U
(
B
_
1
\dynmeet
B
_
2
)
}{
UB
_
2
'
}
\]
\end{enumerate}
\end{lemma}
Which seems to want the following universal property of meets:
\begin{lemma}
[Meets turn a Zag-zig into a Zig-zag]
{
~
}
\begin{enumerate}
\item
For any
$
A
_
1
, A
_
2
$
, the cast through
$
\dynv
$
:
\[
\dncast
{
\u
F A
_
1
}{
\u
F
\dynv
}
\upcast
{
\u
F A
_
2
}{
\u
F
\dynv
}
\]
is equivalent to the cast through
$
\u
F
(
A
_
1
\dynmeet
A
_
2
)
$
:
\[
\upcast
{
\u
F
(
A
_
1
\dynmeet
A
_
2
)
}{
\u
F A
_
1
}
\dncast
{
\u
F
(
A
_
1
\dynmeet
A
_
2
)
}{
\u
F A
_
2
}
\]
\item
For any
$
B
_
1
, B
_
2
$
, the cast through
$
\dync
$
:
\[
\dncast
{
U B
_
1
}{
U
\dync
}
\upcast
{
UB
_
2
}{
U
\dync
}
\]
is equivalent to the cast through
$
B
_
1
\dynmeet
B
_
2
$
:
\[
\upcast
{
U
(
B
_
1
\dynmeet
B
_
2
)
}{
UB
_
1
}
\dncast
{
U
(
B
_
1
\dynmeet
B
_
2
)
}{
UB
_
2
}
\]
\end{enumerate}
\end{lemma}
\end{document}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment