String
实现在速度和内存方面都不高效。据我所知,[] lists
通常在Haskell中作为单链表实现,对于大多数小/简单的数据类型(例如Int
),这似乎不是一个很好的主意,但对于String
来说,这似乎完全是小题大做。关于此事的一些意见包括:
真实世界Haskell
在这样的简单基准测试中,即使是用Python等解释语言编写的程序也可以比使用String的Haskell代码好一个数量级。
Haskell 中的高效字符串实现
由于字符串只是[Char],即Char的链表,这意味着字符串的引用位置很差,这也意味着字符串在内存中相当大,至少是N*(21bits+Mbits),其中N是字符串的长度,M是指针的大小(…)。编译器不太可能将字符串优化为循环等。
我知道Haskell有几种不错的ByteString
s(和Array
s),它们可以很好地完成这项工作,但我希望默认实现是最有效的。
TL;DR:为什么Haskell的默认String
实现是一个单链表,尽管它效率非常低,而且很少用于现实世界的应用程序(除了真正简单的应用程序)?有历史原因吗?它更容易实施吗?
为什么Haskell的默认String实现是一个单链表
因为单链表支持:
- 通过模式匹配进行感应
- 具有有用的属性,如Monad、Functor
- 是适当的参数多态性
- 天生懒惰
因此String
作为[Char]
(unicode点)意味着符合语言目标(自1990年起)的字符串类型,并且基本上与列表库一起"免费"提供。
总之,从历史上看,语言设计者更感兴趣的是设计良好的核心数据类型,而不是文本处理的现代问题,因此我们有一个优雅、易于理解、易于教学的String
类型,它不是一个unicode文本块,也不是一个密集、打包、严格的数据类型。
效率只是衡量抽象的一个轴。虽然列表对于文本操作来说效率很低,但它们非常方便,因为有很多以多态方式实现的列表操作在专门用于[Char]
时具有有用的解释,因此在库实现和用户大脑中都可以获得大量重用。
目前尚不清楚,如果以我们目前的经验水平从头开始设计语言,是否会做出同样的决定;然而,在获得经验之前并不总是能够完美地做出决定。
在这一点上,这可能是历史性的:使ByteString
这样的优化如此高效的优化是最近的,而[Char]
比它们早了很多年。