


@ 468,7 +468,84 @@ unpacking place corresponds to the place, in the previous style, where





the variable would have been first named. Unpacking is a fair price to





pay to recover readable code.










% Acknolwedgements: François Pottier.





\subsection{Another example} To conclude, we would like to demonstrate





the generality of this approach to a wider family of applicative





functions with ``quantifier''like combinators, by briefly showcasing





the same refactoring in a different applicative functor  an





artificial example.










Consider an applicative \lstinline{'a cloud} for ``computations in the





cloud'', where operating on a resources (here a remote file) comes





with a ``cost'' (API usage, time, money, or something else) that is





returned to the programmer when they conclude using the resource. In





this model, opening a (remote) file for reading could be exposed by





the following quantifierlike operation:










\begin{lstlisting}





val with_input : path > (in_channel > 'r cloud) > (cost * 'r) cloud





\end{lstlisting}










and now the user desires to generalize this into a function that opens





a list of paths, operates on the correspond list of input channels,





and returns the sum of all costs (we will assume that





\lstinline{type cost = int} for simplicity). They want to implement:










\begin{lstlisting}





val with_inputs : path list > (in_channel list > 'r cloud) > (cost * 'r) cloud





\end{lstlisting}










and this is tricky. Our proposal, ``turning direct outputs into modal





inputs'', suggests the following change to the primitive operation,





introducing a \lstinline{binder} type that marks the place where





continuationpassingstyle should be used:










\begin{lstlisting}





type ('a, 'r) binder = ('a > 'r cloud) > 'r cloud





val with_input : (in_channel * cost cloud, 'r) binder





\end{lstlisting}










An implementation of \lstinline{with_inputs} using the original API is on the left,





and our proposed approach is on the right.










\hspace{3em}





\begin{minipage}{0.45\linewidth}





\begin{lstlisting}





let rec with_inputs paths k =





match paths with





 [] >





let+ r = k [] in (0, r)





 p :: ps >





let+ (cost_p, (cost_ps, r)) =





let@ chan = with_input p in





let@ chans = with_inputs pts in





k (chan :: chans)





in (cost_p + cost_ps, r)





\end{lstlisting}





\end{minipage}





\hfill





\begin{minipage}{0.55\linewidth}





\begin{lstlisting}





let rec with_inputs paths =





fun k > match paths with





 [] > k ([], pure 0)





 p :: ps >





let@ chan, cost_p = with_input p in





let@ chans, cost_ps = with_input ps in





let+ res = k (p :: ps)





and+ cost_p = cost_p





and+ cost_ps = cost_ps





in (cost_p + cost_ps, res)





\end{lstlisting}





\end{minipage}










Notice, again, that the original API pushes the cost ``on the stack'',





and that the variables \lstinline{cost_p}, \lstinline{cost_ps} are





bound far from the place that logically introduces them in the left





solution. The issue is solved on the right, at the cost of explicit





unpacking of the modal inputs.










\subsection*{Acknowledgments}





We wish to thank François Pottier and our anonymous reviewers for their feedback.










\bibliography{biblio}





\end{document}




