<br><div class="gmail_quote"><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Message: 8<br>
Date: Sat, 5 Mar 2011 00:45:33 +0100<br>
From: Yves Par?s &lt;<a href="mailto:limestrael@gmail.com">limestrael@gmail.com</a>&gt;<br>
Subject: [Haskell-cafe] Use of uninstantiated type class<br>
To: Haskell-Cafe &lt;<a href="mailto:haskell-cafe@haskell.org">haskell-cafe@haskell.org</a>&gt;<br>
Message-ID:<br>
        &lt;AANLkTimBg5TyG6ZNWCKaOT9dP=QE95MtC=<a href="mailto:q_t7RRPQgv@mail.gmail.com">q_t7RRPQgv@mail.gmail.com</a>&gt;<br>
Content-Type: text/plain; charset=&quot;iso-8859-1&quot;<br>
<br>
Hello,<br>
<br>
For testing purposes, I am trying to make an overlay to IO which carries a<br>
phantom type to ensure a context.<br>
I define contexts using empty type classes :<br>
<br>
class CtxFoo c<br>
class CtxBar c<br>
<br>
The overlay :<br>
<br>
newtype MyIO c a = MyIO (IO a)<br>
<br>
Then I define some methods that run only a specific context :<br>
<br>
runFoo :: (CtxFoo c) =&gt; MyIO c a -&gt; IO a<br>
runFoo (MyIO x) = x<br>
<br>
runBar :: (CtxBar c) =&gt; MyIO c a -&gt; IO a<br>
runBar (MyIO x) = x<br>
<br>
And then an action that runs in context &#39;Foo&#39; :<br>
<br>
someAction :: (CtxFoo c) =&gt; MyIO c ()<br>
someAction = putStrLn &quot;FOO&quot;<br>
<br>
Then I run it :<br>
<br>
main = runFoo someAction<br>
<br>
But obiously, GHC complains that my type &#39;c&#39; remains uninstantiated :<br>
<br>
    Ambiguous type variable `c&#39; in the constraint:<br>
      (CtxFoo c) arising from a use of `runFoo&#39;<br>
    Probable fix: add a type signature that fixes these type variable(s)<br>
    In the expression: runFoo someAction<br>
    In an equation for `main&#39;: main = runFoo someAction<br>
<br>
<br>
Is there a way to deal with this ?<br>
The interest of using type classes and not empty types to represent the<br>
contexts is that it stays simple, and that I can do that :<br>
<br>
someAction2 :: (CtxFoo c, CtxBar c) =&gt; MyIO c ()<br>
someAction2 = putStrLn &quot;FOO and BAR&quot;<br>
<br>
... a function that can run in both contexts.<br></blockquote><div><br>You can accomplish this with Rank2Types (and ScopedTypeVariables).  Try this:<br><br>class CtxFoo c<br>class CtxBar c<br><br>data Ctx<br>instance CtxFoo Ctx where<br>
instance CtxBar Ctx where<br><br>runFoo :: forall a. (forall c. (CtxFoo c) =&gt; MyIO c a) -&gt; IO a<br>runFoo x = case (x :: MyIO CtxFooD a) of<br>  (MyIO x&#39;) -&gt; x&#39;<br><br>It&#39;s useful to compare the type of this &quot;runFoo&quot; with the old &quot;runFoo&quot;<br>
<br>*Main&gt; :t runFoo<br>runFoo :: (forall c. CtxFoo c =&gt; MyIO c a) -&gt; IO a<br>*Main&gt; :t runFooOld<br>runBar :: CtxFoo c =&gt; MyIO c a -&gt; IO a<br><br></div></div>Note that the &quot;c&quot; type var is no longer universally quantified.  This means that &quot;runFoo&quot; can&#39;t be used with any actions that specify a concrete context, the action must specify only the &quot;CtxFoo&quot; type class.<br>
<br>There&#39;s a drawback to this approach though.  The number of &quot;run&quot; functions is combinatorial in the number of contexts.  With only two contexts, you already need &quot;runFoo&quot;, &quot;runBar&quot;, and &quot;runFooBar&quot;.  Unless you&#39;ll only ever need a single context, or you won&#39;t need to have combinations of them, this approach quickly grows unwieldy.<br>
<br>John<br>