ListLike包似乎提供你在找什么。我从来不明白为什么它不是更受欢迎。
ListLike除此之外,Prelude中没有实现的一个原因是因为如果不调用某些语言扩展(多参数类型类和fundeps或关联类型),就无法做得很好。有三类容器来考虑:不关心,在他们所有的元素
- 容器(如[])
- 容器,只为特定元素实现(如字节串)
- 集装箱它们是元素上的多态,但需要一个上下文 (例如Data.Vector.Storable,它将使用可存储的 实例保存任何类型的数据。
这里是一个非常基本的ListLike风格类,而无需使用任何扩展:
class Listable container where
head :: container a -> a
instance Listable [] where
head (x:xs) = x
instance Listable ByteString where --compiler error, wrong kind
instance Listable SV.Vector where
head v = SV.head --compiler error, can't deduce context (Storable a)
这里container
有种*->*
。这对于字节串不起作用,因为它们不允许任意类型;他们有种类*
。它也不适用于Data.Vector.Storable向量,因为该类不包含上下文(Storable约束)。
你可以通过改变你的类定义要么解决这个问题
class ListableMPTC container elem | container -> elem where
或
class ListableAT container where
type Elem container :: *
现在container
有种*
;它是一个完全应用的类型构造函数。也就是说,你的实例看起来像
instance ListableMPTC [a] a where
但你不再是Haskell98。
这就是为什么即使是一个简单的Listable类型接口也不重要的原因;当你有不同的集合语义来解释时(例如队列),它会变得更难一些。另一个非常大的挑战是可变数据与不可变数据。到目前为止,我所见过的每一次尝试(除了一次)都会通过创建一个可变接口和一个不可变接口来解决这个问题。我所了解的将这两者统一起来的界面之一是大脑弯曲,引发了一系列扩展,并且性能相当差。
附录:字节串
完全猜想我的一部分,但我认为我们坚持以字节串作为进化的产物。也就是说,它们是低性能I/O操作的第一个解决方案,使用Ptr Word8
来连接IO系统调用是有意义的。对指针的操作需要可存储,并且最有可能的必要扩展(如上所述)使多态性工作不可用。现在很难克服它们的势头。具有多态性的类似容器当然是可能的,可存储的vectorvector包实现了这一点,但它并没有受到任何的欢迎。
字节串是否是多态的,对元素没有任何限制?我认为最接近Haskell的是这个数组类型。这不如低级IO的字节串好,因为数据需要从指针解压缩到数组的内部格式。数据也被装箱,这增加了显着的空间开销。如果你想要无箱的存储空间(更小的空间)和高效的C接口,指针是最好的选择。一旦你有了一个Ptr,你需要Storable,然后你需要在类型类中包含元素类型,所以你需要扩展。这就是说,我认为,通过适当的扩展可用,这对于任何单个容器实现(modulo mutable/immutable API)来说基本上是一个解决的问题。现在比较困难的部分是提出一组可用于许多不同类型结构(列表,数组,队列等)的灵活类,并且足够灵活以实用。我个人预计这会比较简单,但我可能是错的。
你能解释一下你如何想象这方面的工作?由于'[]'有'* - > *'和'ByteString'只是'*',所以显然不可能有一个带'ByteString'和'[]'的类作为实例。 – 2010-09-02 04:25:47
@Travis Brown:你可以用一个简单参数化的newtype包装器来做到这一点。这已经被重新创造了几次,但在这里的例子是http://hackage.haskell.org/packages/archive/iteratee/0.2.1/doc/html/Data-Iteratee-WrappedByteString.html – Anthony 2010-09-02 04:43:39
如果有一个库你想要什么,那么为什么它需要包含在语言本身? – 2010-09-02 04:46:10