I occasionally run into this problem and finally wanted to ask if there's a common solution or pattern. Is it possible to make a type variable in a nested context reference a type from an outer context? For example,
foo :: a -> ... -> ..
foo = ...
where bar :: a -> ...
Now bar
's a
is different than foo's a
. Typically this is what I want, but occasionally it makes life difficult, and I need to make them to be the same. I've used dirty tricks to force the type checker to unify the two in the past, but occasionally get thwarted. Here's my latest example (a Parsec function) that spurred me into finally asking this question.
data Project = ... deriving Enum
data Stuff = ...
pProject :: Monad m => P m Stuff
pProject = do
stuff <- pStuff
...
convert stuff <$> pEnum :: P m Project
pEnum :: (Monad m, Enum a) => String -> P m a
pEnum = ...
The convert
function needed a type, hence I had to specify the annotation :: P m Project
.
However, that means that I have to also introduce the m
, which is unfortunately not the same m
as in the function signature. The type checker reports this with:
Could not deduce
Monad m1
arising from a use ofpEnum
from the contextMonad m
Is there a way to reference the function signature's m
without some ugly hack? (An ugly hack would be inserting dummy code that doesn't get executed, but exists just to unify the two types.)
You're looking for the
ScopedTypeVariables
extension, which lets you reference type variables from containing scopes.For backwards compatibility, it only applies to type signatures that have an explicit
forall
. So you would have to write:After that, you'd be able to refer to the correct type variable
m
inside the scope ofpProject
.