【问题标题】:Implementation of cons/pair [closed]缺点/对的实施[关闭]
【发布时间】:2012-11-02 18:57:11
【问题描述】:

用 C 等低级语言实现 Lisp 的 cons/pair 有哪些选择?

一种常见的实现是由字段 typecarcdr 组成的结构。我知道链表在存储方面效率不高,但是额外的 type 字段会使情况变得更糟。

我在 Wikipedia 上读到 Lisp machines 用于为每个单词添加额外的位以获取类型信息。但是今天的架构(x86、ARM)有哪些选择呢?

【问题讨论】:

  • 你不是基本要实现栈数据结构吗?
  • @bitmask 我猜 Lisp 在幕后可以根据情况使用堆栈或向量而不是列表,但我不确定。
  • @Halst,线性数据结构怎么能满足要求?这是一个 pair,如果我正确地记住了我的 lisp,它甚至可以循环。任何类型的图表都是可能的。我认为不太可能将其设置为 structvoid*[2] 或类似的东西。
  • @JensGustedt 我记得在某处读过现代 Lisp 编译器试图检测何时可以用向量有效地替换列表。虽然它应该是一个适当的列表。

标签: c lisp scheme


【解决方案1】:

Cons 单元格只是我们需要在 Lisp 中表示的一种数据类型。其他的是数组或向量。字符串。人物。数字。符号。记录。类的实例。

不仅 Lisp 机器使用标签位。大多数 Lisp 实现都使用它们。

大多数 Lisp 实现只使用每个内存字中的位。各种 Lisp 机器的每个字的位数不同。 Symbolics 36** 机器使用 36 位字。符号 Ivory 使用 40 位字。 TI Explorer 使用 32 位字。所以 Symbolics 使用了不寻常的字长,而 TI 使用了 normal 字长。 Symbolics 能够使用其 40 位 CPU - 16 GB 处理更多内存。标签使用了 8 位单词。 Symbolics 在表示数据方面也有各种其他优化(例如,列表可以表示为 cdr-coded 向量 - 这种技术在当前的 Lisp 实现中不使用)。

当今的大多数 CPU 都是 32 位或 64 位架构。这使得 Lisp cons 单元格然后是其中两个字的大小,并且位必须适合这些字的大小。 fixnum 小于 32 位或 64 位。 fixnum 是一个整数,它适合一个单词减去标签位。对于较大的整数,数字需要以不同的方式表示。因此,一个完整的 64 位长数字不能表示为 64 位机器上的固定数字。 Common Lisp 提供了有关这些大小的信息。在我的 64 位 LispWorks 上,最正的 fixnum 是 1152921504606846975。

CL-USER > MOST-POSITIVE-FIXNUM
1152921504606846975

为标签位浪费额外的内存是不寻常的。大多数当前的 Lisp 实现必须将标记位放入数据字(32 位或 64 位)中。 Lisp 实现者一直在努力使其尽可能高效。

【讨论】:

  • 补充一些细节,标签位通常在最低有效位置,因此通过将标签位归零,对象指针变为普通指针,假设对象从 2^tagbits 对齐的地址开始.一些实现可能使用多个标签来表示固定编号,例如所有具有低位 0 的标签都是固定编号,因此它可以使用例如32 位平台上的 31 位固定编号。 JavaScript VM 可能会使用 NaN-boxing,因为那里的标准是双精度数,而不是整数。
【解决方案2】:

您可以将type字段替换为指针中的标签。

结合NaN boxing,您可以将每个堆栈槽(以及cons 结构的carcdr 字段)减少到double 的大小。

但是,对于每个 cons 单元格,您仍然会有 malloc 开销(一个或两个字)。

【讨论】:

  • 不一定;如果你观察到 cons 单元的大小是恒定的,你可以用 malloc 分配它们的大块,并使用一个简单的位图来存储哪些正在使用,哪些是空闲的。然后,每个单元块只有一个 malloc 开销。它被称为平板分配器。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 2019-06-04
  • 1970-01-01
  • 2012-04-11
  • 2011-10-07
相关资源
最近更新 更多