为什么 Haskell 的默认字符串实现是字符链表?


众所周知,Haskell的默认String实现在速度和内存方面都不高效。据我所知,[] lists通常在Haskell中作为单链表实现,对于大多数小/简单的数据类型(例如Int),这似乎不是一个很好的主意,但对于String来说,这似乎完全是小题大做。关于此事的一些意见包括:

真实世界Haskell

在这样的简单基准测试中,即使是用Python等解释语言编写的程序也可以比使用String的Haskell代码好一个数量级。

Haskell 中的高效字符串实现

由于字符串只是[Char],即Char的链表,这意味着字符串的引用位置很差,这也意味着字符串在内存中相当大,至少是N*(21bits+Mbits),其中N是字符串的长度,M是指针的大小(…)。编译器不太可能将字符串优化为循环等。

我知道Haskell有几种不错的ByteStrings(和Arrays),它们可以很好地完成这项工作,但我希望默认实现是最有效的。

TL;DR:为什么Haskell的默认String实现是一个单链表,尽管它效率非常低,而且很少用于现实世界的应用程序(除了真正简单的应用程序)?有历史原因吗?它更容易实施吗?

为什么Haskell的默认String实现是一个单链表

因为单链表支持:

  • 通过模式匹配进行感应
  • 具有有用的属性,如Monad、Functor
  • 是适当的参数多态性
  • 天生懒惰

因此String作为[Char](unicode点)意味着符合语言目标(自1990年起)的字符串类型,并且基本上与列表库一起"免费"提供。

总之,从历史上看,语言设计者更感兴趣的是设计良好的核心数据类型,而不是文本处理的现代问题,因此我们有一个优雅、易于理解、易于教学的String类型,它不是一个unicode文本块,也不是一个密集、打包、严格的数据类型。

效率只是衡量抽象的一个轴。虽然列表对于文本操作来说效率很低,但它们非常方便,因为有很多以多态方式实现的列表操作在专门用于[Char]时具有有用的解释,因此在库实现和用户大脑中都可以获得大量重用。

目前尚不清楚,如果以我们目前的经验水平从头开始设计语言,是否会做出同样的决定;然而,在获得经验之前并不总是能够完美地做出决定。

在这一点上,这可能是历史性的:使ByteString这样的优化如此高效的优化是最近的,而[Char]比它们早了很多年。

最新更新