You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
7.4 KiB
288 lines
7.4 KiB
\documentclass{beamer}
|
|
|
|
\usetheme{CambridgeUS}
|
|
|
|
\usepackage[T1]{fontenc}
|
|
\usepackage[utf8]{inputenc}
|
|
|
|
\usepackage{mylistings-slide}
|
|
|
|
\title[API design for type-inference constraints]{Quantified Applicatives \\
|
|
API design for type-inference constraints}
|
|
|
|
\author{\textbf{Olivier Martinot}, Gabriel Scherer}
|
|
\institute[]{PARTOUT team / Inria Saclay}
|
|
|
|
\begin{document}
|
|
|
|
\frame{\titlepage}
|
|
|
|
\begin{frame}{Summary of the work}
|
|
\begin{itemize}
|
|
\item Inferno exposes an applicative functor with quantifier-like functions
|
|
\item We found a difficulty to write certain programs.
|
|
\item We present a change of API that solves it
|
|
|
|
(turn direct outputs into modal inputs)
|
|
\item This applies to any applicative functors with "quantifiers with outputs"
|
|
|
|
\lstinline{('i -> 'c t) -> ('o * 'c) t}
|
|
\end{itemize}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Introduction to Inferno}
|
|
\begin{itemize}
|
|
\item Library developped by François Pottier
|
|
\item Constraint-based type inference
|
|
\item \lstinline{'a co} $ = $ a constraint $ + $ a function that will
|
|
be called with its solution
|
|
\item Applicative functor with quantifiers
|
|
\end{itemize}
|
|
|
|
\pause
|
|
|
|
\begin{block}{Remark}
|
|
\lstinline{'a co} is not a monad.
|
|
|
|
\lstinline{bind : 'a co -> ('a -> 'b co) -> 'b co}
|
|
requires the \lstinline{'a} before we have the \lstinline{'b co} constraint :
|
|
impossible if \lstinline{'a} requires the complete solution.
|
|
\end{block}
|
|
|
|
\begin{block}{Example}
|
|
\lstinline{(x, x + 1)} \hfill\textcolor{gray}
|
|
{unifications coming from the second constraint}
|
|
\end{block}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Code example (with exist)}
|
|
|
|
\begin{lstlisting}
|
|
let<op1> p1 = e1 and<op2> p2 = e2 in body
|
|
==>
|
|
(let<op1>) ((and<op2>) e1 e2) (fun (p1, p2) -> body)
|
|
\end{lstlisting}
|
|
|
|
\pause
|
|
|
|
\begin{lstlisting}
|
|
val exist : (Infer.variable -> 'a co) -> (F.ty * 'a) co
|
|
val (---) : Infer.variable -> Infer.ty -> unit co
|
|
|
|
val (let@) : (('a -> 'c co) -> 'c co)
|
|
-> ('a -> 'c co) -> 'c co
|
|
val (let+) : 'a co -> ('a -> 'b) -> 'b co
|
|
val (and+) : 'a co -> 'b co -> ('a * 'b) co
|
|
\end{lstlisting}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Code example (with exist)}
|
|
\begin{small}
|
|
|
|
\begin{lstlisting}
|
|
let rec hastype
|
|
(t : ML.term) (w : Infer.variable)
|
|
: F.term co
|
|
= match t with
|
|
| [...]
|
|
| ML.Pair (u1, u2) ->
|
|
let+ (ty1, (ty2, (u1', u2'))) =
|
|
let@ v1 = /* \alert<2>{exist}*/ in
|
|
let@ v2 = /* \alert<3>{exist}*/ in
|
|
let+ () = w /*\alert<4>{------}*/ Infer.Prod(v1,v2)
|
|
and+ u1' = hastype u1 v1
|
|
and+ u2' = hastype u2 v2
|
|
in (u1', u2')
|
|
in F.Pair ((u1', ty1), (u2', ty2))
|
|
\end{lstlisting}
|
|
|
|
\begin{lstlisting}
|
|
/*
|
|
\only<2,3>{val \alert{exist} : (Infer.variable -> 'a co) -> (F.ty *\ 'a) co}
|
|
\only<4>{val \alert{(------)} : Infer.variable -> Infer.ty -> unit co}
|
|
*/
|
|
\end{lstlisting}
|
|
|
|
\end{small}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{The problem}
|
|
Generate a arbitrary number of inference variables ?\\
|
|
If \lstinline{'a co} was a monad :
|
|
\begin{lstlisting}
|
|
| ML.Tuple us ->
|
|
let on_each u =
|
|
let@ v = exist in
|
|
let+ v = v
|
|
and+ u' = hastype u v
|
|
in (v, (u', ty))
|
|
in
|
|
mapM on_each us >>= fun vutys ->
|
|
let vs, utys = List.split vutys in
|
|
let+ () = w --- Infer.product vs in
|
|
return (ML.tuple utys)
|
|
\end{lstlisting}
|
|
\begin{block}{}
|
|
\lstinline{'a co} is not a monad, so we are forced to write in continuation
|
|
passing style
|
|
\end{block}
|
|
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Example with another applicative}
|
|
|
|
\begin{itemize}
|
|
\item An applicative \lstinline{'a cloud} for ``computations in the cloud''
|
|
\item Operating on a resource (here a remote file) comes with a ``cost''
|
|
|
|
\begin{lstlisting}[basicstyle=\footnotesize\ttfamily]
|
|
val with_input : path ->
|
|
(in_channel -> 'c cloud) -> (cost * 'c) cloud
|
|
\end{lstlisting}
|
|
\end{itemize}
|
|
|
|
\pause\vfill
|
|
|
|
How to implement the following?
|
|
\begin{lstlisting}[basicstyle=\footnotesize\ttfamily]
|
|
val with_inputs : path list ->
|
|
(in_channel list -> 'c cloud) -> (cost * 'c) cloud
|
|
\end{lstlisting}
|
|
Same issue as the non-static number of \texttt{exist}.
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{CPS solution}
|
|
\begin{lstlisting}[basicstyle=\footnotesize\ttfamily]
|
|
| ML.Tuple us ->
|
|
let rec traverse us (k : variable list -> 'c co)
|
|
: ((F.term * F.ty) list * 'c) co
|
|
= match us with
|
|
| [] -> let+ c = k [] in ([], c)
|
|
| u::us ->
|
|
let+ (ty, (u', (utys, r))) =
|
|
let@ v = exist in
|
|
let+ (utys, (u' r)) = traverse us (fun vs ->
|
|
let+ u' = hastype u v
|
|
and+ r = k (v :: vs)
|
|
in (u', r))
|
|
in (u', (utys, r))
|
|
in ((u', ty) :: utys, r)
|
|
in
|
|
let+ (utys, ()) = traverse us (fun vs ->
|
|
w --- Infer.product vs)
|
|
in F.Tuple utys
|
|
\end{lstlisting}
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{Our proposal: direct outputs => modal inputs}
|
|
|
|
Instead of quantifiers with a direct \emph{output}:
|
|
\begin{lstlisting}
|
|
val old_quantifier : (input -> 'c) -> (/*\alert{output}*/ * 'c) co
|
|
\end{lstlisting}
|
|
|
|
have the continuation take a \emph{modal input} \lstinline{output co}:
|
|
\begin{lstlisting}
|
|
val new_quantifier : (input * /*\alert{output co}*/ -> 'c) -> 'c co
|
|
\end{lstlisting}
|
|
|
|
\pause\vfill
|
|
|
|
For \lstinline{exist}:
|
|
\begin{lstlisting}
|
|
val old_exist : (Infer.variable -> 'c co) -> (/*\alert{F.ty}*/ * 'c) co
|
|
val new_exist : (Infer.variable * /*\alert{F.ty co}*/ -> 'c co) -> 'c co
|
|
\end{lstlisting}
|
|
|
|
\pause\vfill
|
|
|
|
For \lstinline{with_input}:
|
|
\begin{lstlisting}
|
|
val old_with_input : path ->
|
|
(in_channel -> 'c cloud) -> (cost * 'c cloud)
|
|
val new_with_input : path ->
|
|
(in_channel * cost cloud -> 'c cloud) -> 'c cloud
|
|
\end{lstlisting}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{New API}
|
|
|
|
\begin{lstlisting}[basicstyle=\footnotesize\ttfamily]
|
|
type ('a, 'c) binder = ('a -> 'c co) -> 'c co
|
|
val exist : (Infer.variable * F.ty co, 'r) binder
|
|
|
|
val (let@) : ('a, 'c) binder -> ('a -> 'c co) -> 'c co (* identity *)
|
|
val (let+) : 'a co -> ('a -> 'b) -> 'b co (* map *)
|
|
val (and+) : 'a co -> 'b co -> ('a * 'b) co (* pair *)
|
|
\end{lstlisting}
|
|
|
|
\end{frame}
|
|
|
|
\begin{frame}[fragile]{New code example}
|
|
|
|
\hspace{-1em}
|
|
\begin{minipage}{0.5\linewidth}
|
|
\begin{lstlisting}[basicstyle=\tiny\ttfamily]
|
|
| ML.Tuple us ->
|
|
let rec traverse us (k : variable list -> 'c co)
|
|
: ((F.term * F.ty) list * 'c) co
|
|
= match us with
|
|
| [] -> let+ c = k [] in ([], c)
|
|
| u::us ->
|
|
let+ (ty, (u', (utys, r))) =
|
|
let@ v = exist in
|
|
let+ (utys, (u' r)) = traverse us (fun vs ->
|
|
let+ u' = hastype u v
|
|
and+ r = k (v :: vs)
|
|
in (u', r))
|
|
in (u', (utys, r))
|
|
in ((u', ty) :: utys, r)
|
|
in
|
|
let+ (utys, ()) = traverse us (fun vs ->
|
|
w --- Infer.product vs)
|
|
in F.Tuple utys
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\hfill
|
|
\begin{minipage}{0.5\linewidth}
|
|
\begin{lstlisting}[basicstyle=\tiny\ttfamily]
|
|
| ML.Tuple us ->
|
|
let rec traverse (us : ML.term list)
|
|
: (variable list * (F.term * F.ty) list co,
|
|
'r) binder
|
|
= fun k -> match us with
|
|
| [] -> k ([], pure [])
|
|
| u::us ->
|
|
let@ v, ty = exist in
|
|
let@ (vs, us') = traverse us in
|
|
k (v :: vs,
|
|
let+ u' = hastype u v
|
|
and+ ty = ty
|
|
and+ us' = us'
|
|
in (u', ty) :: us')
|
|
in
|
|
let@ (vs, utys) = traverse us in
|
|
let+ () = w --- Infer.product vs
|
|
and+ utys = utys
|
|
in F.Tuple utys
|
|
\end{lstlisting}
|
|
\end{minipage}
|
|
\end{frame}
|
|
|
|
\begin{frame}{Conclusion}
|
|
\begin{itemize}
|
|
\item Turning outputs into modal inputs improve readability
|
|
\item This programming trick applies to other code relying on
|
|
applicative functors with quantifiers
|
|
\end{itemize}
|
|
\begin{block}{}
|
|
Thank you for your attention !
|
|
\end{block}
|
|
\end{frame}
|
|
|
|
\end{document}
|