Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Type variable is not in scope when defining type class

I'm writing a type class à la mtl-style transformers. Looks like this:

class (Monad m, Stream s m t) => MonadStuff s m | m -> s where
  -- function signatures go here…

I'm trying to say by that that m should be instance of Monad and there should be instance of Stream s m t, where t doesn't really matter but s and m are from the right side of the definition (after =>).

Haskell says:

Not in scope: type variable ‘t’

So, obviously I cannot do that. Or can I? Should I remove Stream s m t constraint and add it to every function in the class instead or is there another way?

like image 957
Mark Karpov Avatar asked Oct 19 '22 02:10

Mark Karpov


1 Answers

If it's really true that it doesn't really matter what t is, then perhaps you can ask the person writing the instance to choose it:

{-# LANGUAGE TypeFamilies #-}
class (Monad m, Stream s m (StuffType m)) => MonadStuff s m | m -> s where
    type StuffType m

Or, since you already have MPTCs and fundeps turned on, you could consider doing this, which requires no extra extensions but is otherwise basically identical:

class (Monad m, Stream s m t) => MonadStuff s m t | m -> s t where

However, I am suspicious that in fact the choice of t does matter: unless Stream has a fundep that is at least as informative as m s -> t, you will not be able to use this constraint in a meaningful way. In that case, you should move the constraint into the signatures of the methods that mention t or will be using the Stream methods.

like image 65
Daniel Wagner Avatar answered Oct 22 '22 22:10

Daniel Wagner