Consider the following code,
data MyBaseExpr α where
ConstE :: Show α => α -> MyBaseExpr α
class Monad => MyMonadCls where
type ExprTyp :: * -> *
var :: String -> ExprTyp α -> (ExprTyp α)
expTypArg :: forall α. MyMonadCls => ExprTyp α -> α
expTypArg a = undefined
-- dummy type which will be used as an instance
newtype A α = A ( α)
Then, if one tries to write an instance using the expTypeArg function,
instance forall . (Monad , Monad (A )) => MyMonadCls (A ) where
type ExprTyp (A ) = MyBaseExpr
var nme init@(expTypArg -> typb) =
return init
the compiler complains
Couldn't match type `ExprTyp 0' with `MyBaseExpr'
Expected type: ExprTyp (A ) α
Actual type: ExprTyp 0 α
But, if one adds some scoped type expressions,
instance forall . (Monad , Monad (A )) => MyMonadCls (A ) where
type ExprTyp (A ) = MyBaseExpr
var nme init@((expTypArg :: MyMonadCls (A ) =>
ExprTyp (A ) α ->
(A α)) -> typb) =
return init
then it resolves fine. What’s the problem resolving ExprTyp == MyBaseExpr for expTypArg?
edit
Thanks very much, Daniel! Here’s a way to take some of the verbage out, after noticing that only the type of need be enforced.
ignore_comp :: α -> β -> β
ignore_comp a b = b
instance forall . (Monad , Monad (A )) => MyMonadCls (A ) where
type ExprTyp (A ) = MyBaseExpr
var nme init@(expTypArg -> typb) =
typb `ignore_comp`
return init
ExprTyp is not (necessarily) an injective type function. This means that being handed something of type
ExprType mdoesn’t nail downm— there may also be a differentnsuch thatExprType n = ExprType m. This makes the type ofexpTypArga bit tricky: it uses return-type polymorphism in the same way, e.g.,readdoes, so you’ll need to give extra type annotations to its result in the same situations you have to do withread.