Re: [Haskell-cafe] Rank-2 types in classes
Thanks for your proposal. > It is not clear if the class constraint is really needed. Well 'IM' means 'ImplementationMonad', so it wouldn't make much sense if an IM of an implementation wasn't also a monad. And since IM is the central monad of the library, a lot of functions will use IM. The methods will be spreaded over various classes. For instance the class IWindow : class IWindow i where withinWindow :: Window -> IM i Window a -> IM i x a So a method like 'cast' shouldn't exist, since it would allow the user to switch the context freely. Methods like withinWindow will do that, but safely. 2011/3/3 > > Yves Pare`s wrote: > > 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) > > > > I would like to write something like : > > > > class (forall x. Monad (IM i x)) => Impl i where > > data IM i :: * -> * -> * > > It is not clear if the class constraint is really needed. As an aside, > a class constraint is perhaps a bit of mis-feature of type classes: it sure > improves convenience by making signatures shorter. But it isn't really > necessary. Perhaps there are other, better ways of achieving the > convenience (the constraint alias proposal comes to mind). > > If we drop the class constraint, we can move Monad (IM i x) as the > constraint on specific methods of the Impl class. The implicit uiniversal > quantification on x is well allowed then. For example: > > > class Impl (i :: * -> *) where > > data IM i :: * -> * -> * > > foo :: Monad (IM i x) => Int -> IM i x Int > > bar :: Monad (IM i x) => IM i x Int -> IM i x Bool > > cast :: IM i x a -> IM i y a > > > > data Window > > > > instance Impl IO where > > newtype IM IO x a = IMIO (IO a) > > foo = IMIO . return > > bar (IMIO x) = IMIO (fmap (> 42) x) > > cast (IMIO x) = IMIO x > > > > test :: (Monad (IM i Window), Impl i) => IM i Window Int -> IM i x Bool > > test = cast . bar > > Perhaps this isn't what you had in mind; I more elaborate example > would help then. > ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Rank-2 types in classes
Yves Pare`s wrote: > 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) > > I would like to write something like : > > class (forall x. Monad (IM i x)) => Impl i where > data IM i :: * -> * -> * It is not clear if the class constraint is really needed. As an aside, a class constraint is perhaps a bit of mis-feature of type classes: it sure improves convenience by making signatures shorter. But it isn't really necessary. Perhaps there are other, better ways of achieving the convenience (the constraint alias proposal comes to mind). If we drop the class constraint, we can move Monad (IM i x) as the constraint on specific methods of the Impl class. The implicit uiniversal quantification on x is well allowed then. For example: > class Impl (i :: * -> *) where > data IM i :: * -> * -> * > foo :: Monad (IM i x) => Int -> IM i x Int > bar :: Monad (IM i x) => IM i x Int -> IM i x Bool > cast :: IM i x a -> IM i y a > > data Window > > instance Impl IO where > newtype IM IO x a = IMIO (IO a) > foo = IMIO . return > bar (IMIO x) = IMIO (fmap (> 42) x) > cast (IMIO x) = IMIO x > > test :: (Monad (IM i Window), Impl i) => IM i Window Int -> IM i x Bool > test = cast . bar Perhaps this isn't what you had in mind; I more elaborate example would help then. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Rank-2 types in classes
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 ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Rank-2 types in classes
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 ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Rank-2 types in classes
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 > ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Rank-2 types in classes
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 ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] 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. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe