我正在阅读Learn You a Haskell,我想知道为什么这么多东西都像列表一样,Prelude中没有任何内容使用类型类的本地工具来设置它:
“字节串版本:被称为cons它需要一个字节和一个字节字符串并将字节放在开头。虽然很懒,但即使字节串中的第一个块未满,它也会产生一个新的块这就是为什么最好使用严格版本的cons,cons'如果你要在字节串的开头插入大量的字节。“
为什么没有TypeClass 可列表或提供:
功能来统一Data.ByteString
,Data.List
,Data.ByteString.Lazy
等的内容?这有什么原因,或者这只是传统Haskell的一个元素?使用:
作为一个例子是一种轻描淡写,也来自LYAH:
否则,bytestring模块有一些类似于Data.List中的函数,包括但不限于head,tail,init,null,length,map,reverse,foldl,foldr,concat, takeWhile,filter等。
答案 0 :(得分:28)
ListLike包似乎提供了您正在寻找的内容。我永远不明白为什么它不受欢迎。
除了ListLike之外,在Prelude中没有实现这一点的一个原因是因为如果不调用某些语言扩展(多参数类型类和fundeps或相关类型),这样做是不可能的。有三种容器需要考虑:
这是一个非常基本的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向量,因为该类不包含上下文(可存储约束)。
您可以通过将类定义更改为
来解决此问题class ListableMPTC container elem | container -> elem where
或
class ListableAT container where
type Elem container :: *
现在container
有*
种;它是一个完全应用的类型构造函数。也就是说,您的实例看起来像
instance ListableMPTC [a] a where
但你不再是Haskell98。
这就是为什么即使是一个简单的Listable类型接口也是非平凡的;当你考虑不同的集合语义(例如队列)时,它会变得有点困难。另一个非常大的挑战是可变数据与不可变数据。到目前为止,我所看到的每个尝试(除了一个)都通过创建一个可变接口和一个不可变接口来解决这个问题。我所知道的一个界面确实统一了这两个界面是令人费解的,引用了一堆扩展,并且性能很差。
附录:bytestrings
完全猜测我,但我认为我们坚持使用字节串作为进化的产物。也就是说,它们是低性能I / O操作的第一个解决方案,使用Ptr Word8
与IO系统调用进行交互是有意义的。对指针的操作需要可存储,并且很可能必要的扩展(如上所述)使多态性工作不可用。现在很难克服他们的势头。具有多态性的类似容器当然是可能的,storablevector包实现了这一点,但它并不是那么受欢迎。
字节串是多态的,对元素没有任何限制吗?我认为最接近的Haskell就是Array类型。这不如低级IO的字节串好,因为数据需要从指针解包到数组的内部格式。此外,数据被加框,这增加了大量的空间开销。如果你想要无箱的存储(更少的空间)和与C的有效接口,那么指针就是你要走的路。一旦你有了Ptr,你需要Storable,然后你需要在类型类中包含元素类型,那么你就需要扩展了。
话虽这么说,我认为通过适当的扩展可用,这对于任何单个容器实现(模数可变/不可变API)来说基本上是一个已解决的问题。现在更难的部分是提出一组合理的类,这些类可用于许多不同类型的结构(列表,数组,队列等),并且足够灵活,非常有用。我个人认为这是相对简单的,但我可能是错的。
答案 1 :(得分:17)
这类课程的主要问题是,即使它存在,它只会提供肤浅的相似性。
使用不同结构构建的相同算法的渐近会有很大差异。
在严格的字节串中使用cons构建它们可怕,因为每次添加另一个Char时都会复制整个字符串。列表上的 O(1)操作将其转换为Bytestring上的 O(n)操作。
这会导致 O(n ^ 2)行为,当您实现可能会想到的第一个算法,映射,而构建列表或具有cons的Data.Sequence.Seq是线性时间它可以在 O(n)中实现,用于字节串或向量,以及一点点思考。
事实证明,根据这一点,这类人的效用比实际更为肤浅。
我并不是说找不到好的设计,但是这样的设计难以使用和优化,并且设计的可用版本很可能不会成为Haskell 98。
我已经在我的密钥包中设计了这个设计空间的一部分,这提供了许多用于索引到容器等的功能,但是我故意避免提供类似列表的API a。)因为它已经被之前完成的成功很少b。)因为上面的渐近关注。
tl; dr 当底层操作的渐近性发生变化时,您通常希望以非常不同的方式实现算法。
答案 2 :(得分:14)
提供:函数来统一Data.ByteString,Data.List,Data.ByteString.Lazy等?
已经尝试提出一个好的a)序列接口,和b)容器接口,然而,统一不同类型的数据类型,具有不同的类型约束,通常使得结果非标准到足以使它成为很难想象将它们放在基础库中。类似地,对于数组,尽管Vector包现在具有相当通用的接口(基于关联的数据类型)。
有几个项目可以通过单一界面统一这些不同的半相关数据类型,所以我希望我们很快就能看到结果。同样适用于容器类型。结果不会是微不足道的。
答案 3 :(得分:0)
有两个类型为export default {
data() {
return {
vibrateDuration: 5000,
};
},
methods: {
letsVibrate: function(){
navigator.vibrate(this.vibrateDuration);
}
}
}
和Foldable
的类,它们旨在抽象列表和其他顺序数据结构的一些common1行为。并非所有的数据结构都有这些实例,而且我不知道它们是否对编译器足够透明,以至于它仍然可以对它们进行优化(有人知道这个吗?)
来源:Foldable and Traversable
另见
Why is Haskell missing “obvious” Typeclasses
答案 4 :(得分:0)
实际上在 OverloadedLists
中有一个 IsList
扩展和一个 GHC.Exts
类。
答案 5 :(得分:-1)
ByteString不是泛型类型。
在其他语言中,对于所有类似列表的数据结构,都有类似Sequence
的内容。
我认为这样做有正确的扩展:
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
答案 6 :(得分:-1)
在Haskell中为类似列表的数据创建类型类没有太多价值。为什么? 由于懒惰。您可以编写一个将数据转换为列表的函数,然后使用该列表。该列表只会被构建为需要的子列表和元素,并且只要前缀没有引用,它们的内存就有资格收集。
提供通用toList
函数的类型类有价值 - 但是Data.Foldable
已存在。
基本上,解决方案是实现Data.Foldable
并使用其toList
函数。