Haskell Referencing a Type Variable

599 views Asked by At

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 of pEnum from the context Monad 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.)

1

There are 1 answers

2
Tikhon Jelvis On BEST ANSWER

You're looking for the ScopedTypeVariables extension, which lets you reference type variables from containing scopes.

{-# LANGUAGE ScopedTypeVariables #-}

For backwards compatibility, it only applies to type signatures that have an explicit forall. So you would have to write:

pProject :: forall m. Monad m => P m Stuff

After that, you'd be able to refer to the correct type variable m inside the scope of pProject.