I want to make an instance declaration, but the free type variable is not the last variable. For example, I have a class declaration
class Poppable m where
tryPop :: m a -> Maybe (a, m a)
Now I want to make Q.PSQ (priority queue) an instance of Poppable. Specifically I want something like this:
instance (Ord p) => Poppable (\a -> Q.PSQ a p) where
tryPop = fmap (first Q.key) . Q.minView
However, this is not legal Haskell code. If the order of arguments to PSQ were switched, then I would have no problem:
instance (Ord p) => Poppable (Q.PSQ p) where
tryPop = fmap (first Q.key) . Q.minView
How do I switch the order of arguments for the instance declaration?
Now I could wrap PSQ with a newtype:
newtype PSQ'' a b = PSQ'' (Q.PSQ b a)
However this seems clunky to me because I have to constantly wrap/unwrap it. Is there an easier way?
*
I tried using data/type families, but both give errors.
(1) Using a data family declaration:
data family PSQ' a b
data instance PSQ' a b = PSQ b a
instance (Ord p) => Poppable (PSQ' p) where
tryPop = fmap (first Q.key) . Q.minView
However this gives the error
Couldn't match type `Q.PSQ a p0' with `PSQ' p a'
even though they can match by setting p=p0.
(2) Type families won't work either.
type family PSQ' a b where
PSQ' b a = Q.PSQ a b
gives
Illegal type synonym family application in instance: PSQ' p
Now I could wrap PSQ with a newtype:
newtype PSQ'' a b = PSQ'' (Q.PSQ b a)
However this seems clunky to me because I have to constantly wrap/unwrap it. Is there an easier way?
Nope, not really. You could, of course, write your Poppable
class to make it match PSQ
. And if you like, you can generalize your newtype to
newtype Flip f a b = Flip (f b a)
at which point you could write
instance Poppable (Flip Q.PSQ a)
but none of this will get rid of the underlying annoyance factor. There are reasons Haskell doesn't support this (apparently, it makes inference much harder, sometimes impossible, etc.), so you'll just have to deal with it.
P.S., that type synonym may be more useful poly-kinded, with {-# LANGUAGE PolyKinds #-}
, where it ends up meaning
newtype Flip (f :: k1 -> k2 -> *) (a :: k2) (b :: k1) = Flip (f b a)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With