【发布时间】:2015-03-17 08:00:03
【问题描述】:
我一直在尝试为可以不同索引的列表实现包装器。
此类包装器的基本类:
class List l where
toList :: l a -> [a]
支持索引的包装器:
class Indexed l where
indexed :: (Ix i, List (l i)) => l i a -> [(i, a)]
-- i - type of index
-- l - type of wrapper
可以通过Integral类型索引的列表的包装器:
data IdxByIntList i a = (Ix i, Integral i) => IdxByIntList { getList :: [a] }
如果IdxByIntList 是List 的实例,那么i 是Integral 和Ix:
instance (Integral i, Ix i) => List (IdxByIntList i) where
toList = getList
看起来indexed 函数中的约束(Ix i, Integral i) 已满足,并且可以使IdxByIntList 成为Indexed 的实例:
instance Indexed IdxByIntList where
indexed = zip [0..] . getList
但是不能编译,因为编译器不能推导
将变量 i 键入为 Enum 和 Num 的实例。
编辑:
在indexed 中,对于IdxByIntList,[0..] 具有约束(Num a, Enum a),它转到zip [0..],依此类推,它转到indexed。所以,indexed 应该有约束 (Ix i, Enum i, Num i, List (l i)) 但它不是。
i 是Integral 的实例,所以它是Num 和Enum 的实例。
我希望 Indexed 对其所有实例都有一般约束,并且
具有取决于具体实例的附加约束。在这里,我希望IdxByIntList 在indexed 上有约束(Ix i, List (l i), Integral i)。我该怎么做?
【问题讨论】:
-
不要对构造函数施加约束。
-
如果您将
Integral i添加到indexed的约束中,它会起作用,尽管这可能不是您想要的。问题是(我认为)indexed需要与所有(Ix i, List (l i))一起使用,但您正试图使其与(Ix i, Integral i, List (l i))一起使用。 -
@Cubic,它可以帮助我切断
IdxByIntList的实例,其中i不是Integral和Ix。我为什么要避免它? -
@bheklilr,是的,看起来你是对的。我想我找到了答案。
[0..]有约束(Num a, Enum a)去zip [0..]等等,它去indexed。所以,indexed应该有约束(Ix i, Enum i, Num i, List (l i))但它不是。这就是它无法编译的原因。 -
您可以使用
enumerate = go 0 where go i [] = []; go i (x:xs) = (i, x) : go (i + 1) xs减少限制。这只会将Num的约束放在您的索引上。