Rank-2 types in classes

Hello, I'm working on a library which aims to be a generic interface for 2D rendering. To do that, one of my goals is to enable each implementation of this interface to run in its own monad (most of the time an overlay to IO), thus giving me the following class class (Monad (IM i x)) => Impl i x where data IM i x :: * -> * (where IM means Implementation Monad) Here, 'x' aims at being a phantom type that ensures a type safe context for some operations. E.g., operations that need to occur in a window will have the type: IM i Window a And will be run by the function: withinWindow :: Window -> IM i Window a -> IM i x a This makes an operation that doesn't instantiate 'x' context-independent. My problem, then, is that in the definition of class Impl the type variable 'x' is useless, since every implementation must leave uninstantiated. I would like to write something like : class (forall x. Monad (IM i x)) => Impl i where data IM i :: * -> * -> * But GHC forbids me to do so. Any suggestion would be warmly welcomed.

On 2 March 2011 09:11, Yves Parès
class (forall x. Monad (IM i x)) => Impl i where data IM i :: * -> * -> *
But GHC forbids me to do so.
The way I usually work around this is by doing something like the following pattern: {{{ class Monad1 m where return1 :: a -> m x a bind1 :: m x a -> (a -> m x b) -> m x b instance Monad1 (IM MyI) where return1 = ... bind1 = ... instance Monad1 m => Monad (m x) where return = return1 (>>=) = bind1 }}} Your class can now have a (Monad1 (IM i)) superclass context. You will have to enable a few extensions to get this through - most likely FlexibleInstances and OverlappingInstances. Cheers, Max

Thank you !
Is what I'm trying to do a common technique to type-ensure contexts or are
there simpler methods?
2011/3/2 Max Bolingbroke
On 2 March 2011 09:11, Yves Parès
wrote: class (forall x. Monad (IM i x)) => Impl i where data IM i :: * -> * -> *
But GHC forbids me to do so.
The way I usually work around this is by doing something like the following pattern:
{{{ class Monad1 m where return1 :: a -> m x a bind1 :: m x a -> (a -> m x b) -> m x b
instance Monad1 (IM MyI) where return1 = ... bind1 = ...
instance Monad1 m => Monad (m x) where return = return1 (>>=) = bind1 }}}
Your class can now have a (Monad1 (IM i)) superclass context. You will have to enable a few extensions to get this through - most likely FlexibleInstances and OverlappingInstances.
Cheers, Max

2011/3/2 Yves Parès
Is what I'm trying to do a common technique to type-ensure contexts or are there simpler methods?
I don't understand your problem well enough to be able to venture a solid opinion on this. Sorry! What you have detailed so far doesn't sound too complex, though. Max

The trick is to write the rank-2 type in the function that runs the monad, and leave the typeclasses skolemized. Here's an example: -- | Typeclass for monads that write or read to a network. Useful -- if you define operations that need to work for all such monads. -- You're expected to put extra constraints on h. class (Network g, Monad (m g n), Applicative (m g n), Functor (m g n)) => NetworkMonad m g n where -- | Unsafely converts an 'IO' operation that takes an 'AIG' as an -- argument into an operation in some 'NetworkMonad'. unsafeIOToNetwork :: (GEnv g -> IO a) -> m g n a ... class OpaqueNetwork g => Network g where -- * We cannot put NetworkMonad constraint on GNT g and GNQ g because we -- need to be able to put that constraint as a rank-2 monad. -- * This has a lot of "stuff" in it, maybe we'll split it up later. data GNode g :: * -- ^ phantom type -> * -- ^ data type data GNT g :: * -- ^ phantom type -> * -> * -- ^ monad data GNQ g :: * -- ^ phantom type -> * -> * -- ^ monad data GEnv g :: * one :: GNode g n zero :: GNode g n runNT :: (forall n. NetworkMonad GNT g n => GNT g n ()) -> g withNT :: g -> (forall n. NetworkMonad GNT g n => GNT g n ()) -> g There are numerous other problems with this route (can you see them from the sample code?) but I found this solution to be mostly acceptable. Cheers, Edward
participants (3)
-
Edward Z. Yang
-
Max Bolingbroke
-
Yves Parès