Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Linking/Combining Type Classes in Haskell

Say I have two type classes defined as follows that are identical in function but different in names:

class Monad m where
    (>>=)  :: m a -> (a -> m b) -> m b
    return :: a -> m a

class PhantomMonad p where
    pbind    :: p a -> (a -> p b) -> p b
    preturn  :: a -> p a

Is there a way to tie these two classes together so something that is an instance of PhantomMonad will automatically be an instance of Monad, or will instances for each class have to be explicitly written? Any insight would be most appreciated, thanks!

like image 632
thegravian Avatar asked May 20 '10 19:05

thegravian


2 Answers

Good answer: No, what you're hoping to do isn't really viable. You can write an instance that looks like it does what you want, possibly needing some GHC extensions in the process, but it won't work the way you you'd like it to.

Unwise answer: You can probably accomplish what you want using scary type-level metaprogramming, but it may get complicated. This really isn't recommended unless you absolutely need this to work for some reason.

Officially instances can't really depend on other instances, because GHC only looks at the "instance head" when making decisions, and class constraints are in the "context". To make something like a "type class synonym" here, you'd have to write what looks like an instance of Monad for all possible types, which obviously doesn't make sense. You'll be overlapping with other instances of Monad, which has its own problems.

On top of all that, I don't think such an instance will satisfy the termination check requirements for instance resolution, so you'd also need the UndecidableInstances extension, which means the ability to write instances that will send GHC's type checker into an infinite loop.

If you really want to go down that rabbit hole, browse around on Oleg Kiselyov's website a bit; he's sort of the patron saint of type-level metaprogramming in Haskell.

It's fun stuff, to be sure, but if you just want to write code and have it work, probably not worth the pain.

Edit: Okay, in hindsight I've overstated the issue here. Something like PhantomMonad works fine as a one-off and should do what you want, given the Overlapping- and UndecidableInstances GHC extensions. The complicated stuff starts up when you want to do anything much more complicated than what's in the question. My sincere thanks to Norman Ramsey for calling me on it--I really should have known better.

I still don't really recommend doing this sort of thing without good reason, but it's not as bad as I made it sound. Mea culpa.

like image 50
C. A. McCann Avatar answered Sep 20 '22 22:09

C. A. McCann


That's an unusual design. Can you not just remove the PhantomMonad, since it is isomorphic to the other class.

like image 33
Don Stewart Avatar answered Sep 23 '22 22:09

Don Stewart