<div class="gmail_quote">On Mon, Jun 22, 2009 at 7:27 PM, Tim Sheard <span dir="ltr">&lt;<a href="mailto:sheard@cs.pdx.edu">sheard@cs.pdx.edu</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">


My idea is to use types to ensure that any<br>
sequence of operations adheres to a path on<br>
a finite state automata. For example<br>
if we wanted to implement the following<br>
automata (This needs to read in a fixed width font)<br>
</blockquote><div><br>Here&#39;s the reply Oleg gave me when I asked about using monadic regions to enforce similar constraints (published with Oleg&#39;s permission):<br></div></div><br>Oleg writes:<br>&gt;        First of all, protocols of using API functions are essentially<br>

&gt; session types, right? Thus various implementations of session types<br>&gt; could be taken advantage of (including the one presented by Jesse Tov<br>&gt; on Haskell 2008 Symposium). Aliasing is responsible for a lot of the<br>

&gt; complexity: if the variable &#39;s&#39; is bound to a value of the type socket<br>&gt; and we execute &quot;do s&#39; &lt;- bindS s&quot; so to bind the socket, the old<br>&gt; variable s is still available and could be used. But it should not be<br>

&gt; used because bindS &quot;consumed&quot; the unbound socket and produced the new<br>&gt; one. To properly describe these resource restrictions (a resource can<br>&gt; be consumed and after that it is not available any more), we need<br>

&gt; linear, affine or various other kinds of substructural logics and type<br>&gt; systems. It seems they all can be emulated in Haskell, but with some<br>&gt; hackery (see for example Sec 6 of our monadic regions<br>&gt; paper). Parameterized monads are necessary.<br>

&gt; <br>&gt;        The lightweight monadic regions paper relied on a simple<br>&gt; session protocol: open -&gt; (read+write)* -&gt; close. That protocol can be<br>&gt; ensured without parameterized monads: the only aliasing to mind is<br>

&gt; the accessibility of the file handle after the closing operation. We<br>&gt; can get rid of `close&#39; (make it implicit ar region&#39;s exit) and use<br>&gt; rank-2 types to prevent file handles from leaking out. There is some<br>

&gt; dynamic overhead, in the function open. However, the most frequent<br>&gt; operation, reading and writing from the handle, involves no overhead<br>&gt; and its correctness ensured statically.<br>&gt; <br>&gt;        That design can be extended to sockets. For example:<br>

&gt; <br>&gt; data Socket sort = Socket Int<br>&gt; <br>&gt; data UnconnectedSocket<br>&gt; data ConnectedSocket s<br>&gt; <br>&gt; connect :: RMonadIO (m s) =&gt; SocketProto -&gt; SAddress -&gt;<br>&gt;        m s (Socket (ConnectedSocket s))<br>

&gt; <br>&gt; sendto :: RMonadIO (m s) =&gt; (Socket (ConnectedSocket s)) -&gt; Buffer<br>&gt;        -&gt; m s (ReturnCode)<br>&gt; <br>&gt; -- polymorphic in the socket sort<br>&gt; send :: MonadIO m =&gt; Socket sort -&gt; Buffer -&gt; m ReturnCode<br>

&gt; <br>&gt; <br>&gt; In this design, the operation of creating a socket and connecting it<br>&gt; are bundled together -- which is very common and is the case for<br>&gt; System V, I think (where it is called openActive, I think). If you for<br>

&gt; some reason want to keep &#39;socket&#39; and &#39;connect&#39; separate, then<br>&gt; &#39;connect&#39; has to check at run-time that the socket in question is not<br>&gt; connected yet. Still, the most common operations like send and write<br>

&gt; should be overhead-free.<br><br>Cheers,<br><br>Johan<br><br>