我想创建一个实例声明,但free类型变量不是最后一个变量.例如,我有一个类声明
class Poppable m where
tryPop :: m a -> Maybe (a, m a)
Run Code Online (Sandbox Code Playgroud)
现在我想让Q.PSQ(优先级队列)成为Poppable的一个实例.具体来说,我想要这样的东西:
instance (Ord p) => Poppable (\a -> Q.PSQ a p) where
tryPop = fmap (first Q.key) . Q.minView
Run Code Online (Sandbox Code Playgroud)
但是,这不是合法的Haskell代码.如果切换到PSQ的参数顺序,那么我就没有问题了:
instance (Ord p) => Poppable (Q.PSQ p) where
tryPop = fmap (first Q.key) . Q.minView
Run Code Online (Sandbox Code Playgroud)
如何切换实例声明的参数顺序?
现在我可以使用newtype包装PSQ:
newtype PSQ'' a b = PSQ'' (Q.PSQ b a)
Run Code Online (Sandbox Code Playgroud)
然而这对我来说似乎很笨重,因为我必须不断地包装/打开它.有没有更简单的方法?
*
我尝试使用数据/类型系列,但都给出了错误.
(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
Run Code Online (Sandbox Code Playgroud)
然而,这给出了错误
Couldn't match type `Q.PSQ a p0' with `PSQ' p a'
Run Code Online (Sandbox Code Playgroud)
即使它们可以通过设置p = p0来匹配.
(2)类型系列也不起作用.
type family PSQ' a b where
PSQ' b a = Q.PSQ a b
Run Code Online (Sandbox Code Playgroud)
给
Illegal type synonym family application in instance: PSQ' p
Run Code Online (Sandbox Code Playgroud)
现在我可以使用newtype包装PSQ:
Run Code Online (Sandbox Code Playgroud)newtype PSQ'' a b = PSQ'' (Q.PSQ b a)然而这对我来说似乎很笨重,因为我必须不断地包装/打开它.有没有更简单的方法?
不,不是真的.当然,您可以编写您的Poppable课程以使其匹配PSQ.如果你愿意,你可以将你的新类型推广到
newtype Flip f a b = Flip (f b a)
Run Code Online (Sandbox Code Playgroud)
那时你可以写
instance Poppable (Flip Q.PSQ a)
Run Code Online (Sandbox Code Playgroud)
但这些都不能摆脱潜在的烦恼因素.有一些原因Haskell不支持这一点(显然,它使推理更难,有时甚至不可能等),所以你只需要处理它.
PS,这种类型的同义词可能更有用,多边形{-# LANGUAGE PolyKinds #-},最终意义
newtype Flip (f :: k1 -> k2 -> *) (a :: k2) (b :: k1) = Flip (f b a)
Run Code Online (Sandbox Code Playgroud)