我想做一个实例声明,但是自由类型变量不是最后一个变量。例如,我有一个类声明

class Poppable m where
  tryPop :: m a -> Maybe (a, m a)

现在,我想将Q.PSQ(优先级队列)作为Poppable的实例。具体来说,我想要这样的东西:
instance (Ord p) => Poppable (\a -> Q.PSQ a p) where
  tryPop = fmap (first Q.key) . Q.minView

但是,这不是合法的Haskell代码。如果切换到PSQ的参数顺序,那么我将没有问题:
instance (Ord p) => Poppable (Q.PSQ p) where
  tryPop = fmap (first Q.key) . Q.minView

如何切换实例声明的参数顺序?

现在我可以用新类型包装PSQ了:
newtype PSQ'' a b = PSQ'' (Q.PSQ b a)

但是,这对我来说似乎很笨拙,因为我必须不断包装/拆开包装。有没有更简单的方法?

*

我尝试使用数据/类型系列,但都给出了错误。

(1)使用数据族声明:
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

但这给出了错误
Couldn't match type `Q.PSQ a p0' with `PSQ' p a'

即使可以通过设置p = p0进行匹配。

(2)类型家庭也不起作用。
type family PSQ' a b where
  PSQ' b a = Q.PSQ a b


Illegal type synonym family application in instance: PSQ' p

最佳答案

现在我可以用新类型包装PSQ了:

newtype PSQ'' a b = PSQ'' (Q.PSQ b a)
但是,这对我来说似乎很笨拙,因为我必须不断包装/拆开包装。有没有更简单的方法?

不,不是这样。当然,您可以编写Poppable类使其与PSQ相匹配。如果愿意,可以将新类型推广到
newtype Flip f a b = Flip (f b a)
在那时你可以写
instance Poppable (Flip Q.PSQ a)
但这些都不能消除潜在的烦恼因素。有很多原因,Haskell不支持此操作(显然,这使推理变得更加困难,有时甚至是不可能的,等等),因此您只需要处理它即可。
附言:这种类型的同义词可能更有用,与{-# LANGUAGE PolyKinds #-}一起使用,它的最终含义是
newtype Flip (f :: k1 -> k2 -> *) (a :: k2) (b :: k1) = Flip (f b a)

09-26 02:30