List 在哈斯克尔,为什么不是';对于可以像列表一样工作的事物,没有类型类吗?
我正在阅读,我想知道为什么这么多事情都像一个列表,而前奏曲中没有使用类型类的本机功能来设置: :的bytestring版本称为cons,它接受一个字节和一个bytestring,并将字节放在开头。但它是惰性的,因此即使bytestring中的第一个块未满,它也会生成一个新块。这就是为什么最好使用cons的严格版本,如果要在bytestring的开头插入大量字节,那么最好使用cons的严格版本。” 为什么没有一个TypeClass listable或者提供了List 在哈斯克尔,为什么不是';对于可以像列表一样工作的事物,没有类型类吗?,list,haskell,typeclass,List,Haskell,Typeclass,我正在阅读,我想知道为什么这么多事情都像一个列表,而前奏曲中没有使用类型类的本机功能来设置: :的bytestring版本称为cons,它接受一个字节和一个bytestring,并将字节放在开头。但它是惰性的,因此即使bytestring中的第一个块未满,它也会生成一个新块。这就是为什么最好使用cons的严格版本,如果要在bytestring的开头插入大量字节,那么最好使用cons的严格版本。” 为什么没有一个TypeClass listable或者提供了:函数来统一数据。ByteString,
:
函数来统一数据。ByteString
,数据。List
,数据。ByteString。Lazy
,等等?这有什么原因吗,或者这仅仅是遗留Haskell的一个元素?使用:
作为一个例子是一种轻描淡写,同样来自LYAH:
否则,bytestring模块具有一系列类似于Data.List中的函数,包括但不限于head、tail、init、null、length、map、reverse、foldl、foldr、concat、takeWhile、filter等
它提供了:统一Data.ByteString、Data.List、Data.ByteString.Lazy等的函数
有人试图设计出一个好的a)序列接口和b)容器接口,但是,统一不同类型、具有不同类型约束的数据类型,通常会使结果不够标准,很难想象将它们放在基本库中。同样,对于数组,尽管现在使用向量包具有相当通用的接口(基于关联的数据类型)
有几个项目可以用一个接口统一这些不同的半相关数据类型,所以我希望我们很快就会看到结果。对于容器类型也是如此。但结果不会是微不足道的。这个包似乎提供了您想要的东西。我一直不明白为什么它不那么流行
撇开ListLike不谈,Prelude中没有实现这一点的一个原因是,如果不调用一些语言扩展(多参数类型类和FundeP或相关类型),就不可能做到这一点。有三种容器需要考虑:
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)
class Seq a b | a -> b where
head :: a -> b
isTail :: a -> Bool
# ([a]) is a sequence of a's
instance Seq [a] a where
head (x:xs) = x
isTail = (== [])
# ByteString is a sequence of chars
instance Seq ByteString Char
这里的容器
具有种类*->*
。这不适用于ByTestRing,因为它们不允许任意类型;它们具有种类*
。它也不适用于Data.Vector.Storable Vector,因为类不包含上下文(可存储约束)
您可以通过将类定义更改为
class ListableMPTC container elem | container -> elem where
或
现在,container
具有种类*
;它是一个完全应用的类型构造函数
instance ListableMPTC [a] a where
但你已经不再是一个单身汉了
这就是为什么即使是一个简单的Listable类型接口也很重要的原因;当需要考虑不同的集合语义(例如队列)时,它会变得有点困难。另一个真正大的挑战是可变与不可变的数据。到目前为止,我所看到的每一次尝试(除了一次)通过创建一个可变接口和一个不可变接口来解决这个问题。我所知道的一个接口将这两个接口统一了起来,这是一个令人费解的接口,它调用了一系列扩展,性能非常差
附录:BYTESTRING
这完全是我的猜测,但我认为ByTestring是进化的产物。也就是说,它们是低性能I/O操作的第一个解决方案,使用Ptr Word8
s与IO系统调用接口是有意义的。指针上的操作需要可存储的,而且很可能需要必要的扩展(如上所述)使多态性发挥作用在当时是不可用的。现在很难克服它们的势头。一个具有多态性的类似容器当然是可能的,storablevector包实现了这一点,但它远没有那么流行
bytestring是否可以在不限制元素的情况下具有多态性?我认为Haskell与此最接近的是数组类型。对于低级别IO,这远不如bytestring好,因为需要将数据从指针解压到数组的内部格式。此外,数据被装箱,这会增加大量的空间开销。I如果您想要无绑定存储(更少的空间)和与C的高效接口,指针就是最好的选择。一旦您有了Ptr,您需要可存储,然后您需要在类型类中包含元素类型,这样您就只需要扩展了
话虽如此,我认为有了适当的扩展,这对于任何单个容器实现(模可变/不可变API)来说本质上都是一个已解决的问题。现在更难的部分是提出一组合理的类,这些类可用于许多不同类型的结构(列表、数组、队列等)我个人认为这是相对简单的,但我可能错了。ByteString不是泛型类型 在其他语言中,对于所有类似列表的数据结构,都有类似于
Sequence
。
我认为这是可行的,有正确的扩展:
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)
class Seq a b | a -> b where
head :: a -> b
isTail :: a -> Bool
# ([a]) is a sequence of a's
instance Seq [a] a where
head (x:xs) = x
isTail = (== [])
# ByteString is a sequence of chars
instance Seq ByteString Char
还是试试这个
type BS a = ByteString
instance List BS
在Haskell中为类似列表的数据创建一个类型类没有多大价值。为什么?是因为懒惰。您只需编写一个函数,将数据转换为列表,然后使用该列表。列表只会在需要其子列表和元素以及它们的内存时构建