Message: 8
Date: Sat, 5 Mar 2011 00:45:33 +0100
From: Yves Par?s <limestrael@gmail.com>
Subject: [Haskell-cafe] Use of uninstantiated type class
To: Haskell-Cafe <haskell-cafe@haskell.org>
Message-ID:
<AANLkTimBg5TyG6ZNWCKaOT9dP=QE95MtC=q_t7RRPQgv@mail.gmail.com>
Content-Type: text/plain; charset="iso-8859-1"
Hello,
For testing purposes, I am trying to make an overlay to IO which carries a
phantom type to ensure a context.
I define contexts using empty type classes :
class CtxFoo c
class CtxBar c
The overlay :
newtype MyIO c a = MyIO (IO a)
Then I define some methods that run only a specific context :
runFoo :: (CtxFoo c) => MyIO c a -> IO a
runFoo (MyIO x) = x
runBar :: (CtxBar c) => MyIO c a -> IO a
runBar (MyIO x) = x
And then an action that runs in context 'Foo' :
someAction :: (CtxFoo c) => MyIO c ()
someAction = putStrLn "FOO"
Then I run it :
main = runFoo someAction
But obiously, GHC complains that my type 'c' remains uninstantiated :
Ambiguous type variable `c' in the constraint:
(CtxFoo c) arising from a use of `runFoo'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: runFoo someAction
In an equation for `main': main = runFoo someAction
Is there a way to deal with this ?
The interest of using type classes and not empty types to represent the
contexts is that it stays simple, and that I can do that :
someAction2 :: (CtxFoo c, CtxBar c) => MyIO c ()
someAction2 = putStrLn "FOO and BAR"
... a function that can run in both contexts.
You can accomplish this with Rank2Types (and ScopedTypeVariables). Try this:
class CtxFoo c
class CtxBar c
data Ctx
instance CtxFoo Ctx where
instance CtxBar Ctx where
runFoo :: forall a. (forall c. (CtxFoo c) => MyIO c a) -> IO a
runFoo x = case (x :: MyIO CtxFooD a) of
(MyIO x') -> x'
It's useful to compare the type of this "runFoo" with the old "runFoo"
*Main> :t runFoo
runFoo :: (forall c. CtxFoo c => MyIO c a) -> IO a
*Main> :t runFooOld
runBar :: CtxFoo c => MyIO c a -> IO a
Note that the "c" type var is no longer universally quantified. This means that "runFoo" can't be used with any actions that specify a concrete context, the action must specify only the "CtxFoo" type class.