Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell Referencing a Type Variable

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.)

like image 843
Tim Avatar asked Dec 06 '14 00:12

Tim


People also ask

How do you assign a type in Haskell?

Haskell has three basic ways to declare a new type: The data declaration, which defines new data types. The type declaration for type synonyms, that is, alternative names for existing types. The newtype declaration, which defines new data types equivalent to existing ones.

How do you define a data type in Haskell?

The Data Keyword and Constructors In general, we define a new data type by using the data keyword, followed by the name of the type we're defining. The type has to begin with a capital letter to distinguish it from normal expression names. To start defining our type, we must provide a constructor.

How do I check my type in Haskell?

If you need to figure out what the type of an object is in a Haskell program, I hope this is helpful. Note that if you are in GHCI, you can just put :type before your expression to determine the expression's type, or use :set +t to see the type of every expression in GHCI.

Does Haskell pass by reference?

No, Haskell is not pass-by-reference. Nor is it pass-by-value. Pass-by-reference and pass-by-value are both strict evaluation strategies, but Haskell is non-strict.


1 Answers

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.

like image 65
Tikhon Jelvis Avatar answered Sep 28 '22 15:09

Tikhon Jelvis