I have this typeclass:
class Monad m => Convertible m a b where
convert :: a -> m b
For many pairs of types, the conversion can be done purely, without requiring a monadic effect.
Now, I know I can write a related typeclass like
class PureConvertible a b where
convertPurely :: a -> b
and then make one a superclass of the other, and/or define instances of one in terms of the other using DerivingVia
.
But the question is about something different. What if I define a type synonym like
import Data.Kind
type PureConvertible :: Type -> Type -> Constraint
type PureConvertible a b = forall m . Monad m => Convertible m a b
The idea is that I could perhaps avoid mentioning m
when defining Convertible
instances, if my conversion doesn't require the features of any concrete monad. An attempt:
instance PureConvertible Int String where
convert _ = pure undefined
Alas, this doesn't compile. The error is:
‘convert’ is not a (visible) method of class ‘PureConvertible’
Curiously enough, if I remove the convert
method from the typeclass, the following compiles!
class Monad m => Convertible m a b where
type PureConvertible :: Type -> Type -> Constraint
type PureConvertible a b = forall m . Monad m => Convertible m a b
instance PureConvertible Int String where
Is there a way to make this type synonym that hides m
work, when there are methods in the typeclass?
I'm using GHC 9.2.4. Some language pragmas which might be useful:
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE StandaloneKindSignatures #-}
Not a direct answer to your question, but I would suggest:
The amount of boilerplate is minimal, and the compiler should do a good job of optimizing the
Identity
-related fluff away.