【发布时间】:2015-06-24 02:49:22
【问题描述】:
我有一个队列类,它允许实例定义它对元素的约束。例如,优先级队列要求其元素是可排序的:
{-# LANGUAGE MultiParamTypeClasses, ConstraintKinds, FunctionalDependencies #-}
class Queue q c | q -> c where
empty :: q a
qpop :: c a => q a -> Maybe (a, q a)
qpush :: c a => a -> q a -> q a
data PriorityQueue a = ...
instance Queue PriorityQueue Ord where
...
这很有魅力:在PriorityQueue 的实例声明中,我可以使用Ord 的成员对队列元素进行操作,例如(>)。
我一直在尝试定义一个对其元素没有要求的队列:
newtype LIFO a = LIFO [a]
instance Queue LIFO () where
empty = LIFO []
qpop (LIFO []) = Nothing
qpop (LIFO (x:xs)) = Just (x, LIFO xs)
qpush x (LIFO xs) = LIFO $ x:xs
这失败了,来自 GHC 的错误消息如下:
The second argument of `Queue' should have kind `* -> Constraint',
but `()' has kind `*'
In the instance declaration for `Queue LIFO ()'
此错误消息对我来说很有意义。 Eq 接受类型参数(我们通常写成 Eq a => ...),而 () 没有参数 - 这是一个普通的旧类型不匹配。
我在编写忽略其第二个参数的类型函数时遇到了难题,这将允许我编写instance Queue LIFO (Const ()):
{-# LANGUAGE TypeFamilies, KindSignatures, PolyKinds #-}
type family Const a b :: k -> k2 -> k
type instance Const a b = a
我发现类型族和类型多态的这种交互非常漂亮,所以当它不起作用时我很失望(我真的以为它会!):
Expecting two more arguments to `a'
The first argument of `Const' should have kind `*',
but `a' has kind `k0 -> k1 -> k0'
In the type `a'
In the type instance declaration for `Const'
我觉得最后一个例子有点像语法错误一样愚蠢(我是类型族的新手)。我怎样才能写出不对其论点施加任何限制的Constraint?
【问题讨论】:
-
尝试定义
type family Const (a :: k1) (b :: k2) :: k1然后Const (() :: Constraint)有你想要的那种,但它仍然卡住。 -
@J.Abrahamson 是的,它似乎卡在
instance声明中:Illegal type synonym family application in instance。为什么我最初在Const的尝试失败了? -
您可能也有兴趣使用
TypeFamilies进行此操作。 skybluetrades.net/blog/posts/2015/03/08/… -
@snak 感谢您的链接。这看起来像是将我的
FunctionalDepenencies版本直接翻译成TypeFamilies。 (这是非常合理的,因为类型族概括了函数依赖。)我个人更喜欢这里的函数依赖,但这纯粹是一个品味问题。
标签: haskell typeclass type-constraints type-families