I'm trying to write something that appears to be analagous to "rank 2 types", but for constraints instead. (Or, maybe it's not correct to assume changing ->
in the definition of "rank 2 types" to =>
is meaningful; please edit the question if you think up better terminology).
setup
First, the Suitable
typeclass (from Data.Suitable, the base of rmonad) can be used to denote types of values which can be used. In this question, I'll use
Suitable m a
to denote that value a
can be used as a value for some functions of the monad m
(in particular, if m
is a DSL, then its values are usually a
which are suitable), for example
class PrintSuitable m where
printSuitable :: Suitable m a => a -> m ()
See the top comment for RMonad [ link ] and its source for an example of how to use Suitable. For example, one could define Suitable m (Map a b)
, and print the number of elements in the map.
question
goal: Now, I have a monad transformer MyMonadT
, and want to make MyMonadT m
a PrintSuitable
instance whenever m
is a PrintSuitable
instance.
rank 2 constraints motivation: The issue is that the type a
is introduced with regard to the printSuitable
function, i.e. does not appear in the class
signature. Since one can only add constraints to the class
signature (additional constraints to an instance
function implementation are illegal), it makes sense to say something about all a
in the class signature (line 2 below).
Below shows the intended code.
instance (PrintSuitable m, MonadTrans t,
(forall a. Suitable (t m) a => Suitable m a), -- rank 2 constraint
) => PrintSuitable (t m) where
printSuitable = lift ...
-- MyMonadT doesn't change what values are Suitable, hence the rank 2 expression,
-- (forall a. Suitable (t m) a => Suitable m a) should hold true
data instance Constraints (MyMonadT m) a =
Suitable m a => MyMonadT_Constraints
instance Suitable m a => Suitable (MyMonadT m) a where -- the important line
constraints = MyMonadT_Constraints
instance MonadTrans MyMonadT where ...
-- now, MyMonadT m is a PrintSuitable whenever m is a PrintSuitable
-- the manual solution, without using MonadTrans, looks roughly like this
instance PrintSuitable m => PrintSuitable (t m) where
printSuitable a = withResConstraints $ \MyMonadT_Constraints -> ...
the constraint indicated says that anything that's suitable in (t m)
is suitable in m
. But, of course, this isn't valid Haskell; how could one encode a functional equivalent?
Thanks in advance!!!
PrintSuitable
a two-parameter class? – Mycobacteriumrmonad
. You get mired if you have a functiona -> b
, want to writea -> m b
, etc. (you'll probably get a better explanation by trying to write theSet
rmonad without Suitable.) – InterlocutrixQuantifiedConstraints
, for exampleMonadTrans tr
just got an implication constraint for a superclass:class (forall m. Monad m => Monad (tr m)) => MonadTrans tr
– Totaquine