[Haskell-cafe] Problem with result-type context restrictions in typeclasses.

Miguel Mitrofanov miguelimo38 at yandex.ru
Wed Sep 30 03:00:22 EDT 2009


> class Cls c where
>    type Ret c :: (Bar *) => * -- or a better name
>    foo :: c -> Ret c
> 
> which isn't legal Haskell.

OK, that's exactly the same thing I've met when developing 
compose-trans. I needed guarantees that something is a Monad.

My way of doing that was to make "Bar" ("Monad" in my case) a datatype.

Suppose you "Bar" class is something like

class Bar c where
     toBar :: String -> c
     changeBar :: c -> Int -> c
     fromBar :: c -> c -> [Float]

Declare something like

data BarD c =
     BarD
         {toBarD :: String -> c,
          changeBarD :: c -> Int -> c,
          fromBarD :: c -> c -> [Float]}

I've did it some other way, using the Monad specifics, but essentially 
it was the same.

Then you can write a default "BarD" this way:

barDInst :: Bar c => BarD c
barDInst =
     BarD
         {toBarD = toBar,
          changeBarD = changeBar,
          fromBarD = fromBar}


Do not (!) export BarD constructor, so the only BarD one would be able 
to produce would be the default one. It simplifies you interface.

Now, your "Cls" looks like that:

class Cls c where
     type Ret c
     barRet :: BarD (Ret c)
     foo :: c -> Ret c

If somebody is using your class, she can't be sure that "Ret c" is of 
class "Bar", but she would have sort of an instance anyway: she would 
just use "toBarD barRet" instead of "toBar", and so on. If somebody is 
trying to make some "c" an instance of "Cls" - the only thing she can do 
is to make some "d" an instance of "Bar" and write

instance Cls MyCoolInstance where
     type Ret MyCoolInstance = MyCoolRetType
     barRet = barDInst
     foo c = ...

It's higly possible, however, that you'd have to deal with "Ambiguous 
type variable"'s.


More information about the Haskell-Cafe mailing list