[Haskell-cafe] Rank-2 types in classes

Edward Z. Yang ezyang at MIT.EDU
Thu Mar 3 01:43:26 CET 2011


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



More information about the Haskell-Cafe mailing list