5

问题

我想创建一个数据类型,它允许快速访问和修改其元素。是否可以在 Haskell 中创建一个结构和函数,其执行速度与简单的 C++ 实现一样快?

问题详情

我正在用 Haskell 编写一个编译器。我已经用数据类型表示AST,让我们考虑以下一个:

import Prelude hiding (id)

-- this is a sample data type, the real one has got a lot of constructors
data AST = A { id :: Int, x :: AST, y :: AST, z :: AST }
         | B { id :: Int }
         | C { id :: Int, x :: AST, y :: AST }
         | D { id :: Int, u :: AST, v :: AST, w :: AST}

每个 AST 节点都有一个唯一的标识符。我很想在 Haskell 中实现以下功能:

  • 一个函数getById,它将返回一个O(1)时间复杂度为选定 id 的 AST 节点。
  • 能够在结构上创建“焦点”并相互独立地修改焦点元素。所以我希望能够记住一些子树的焦点,并能够在O(1)时间复杂度上修改每个这样的焦点。

我在考虑Zippers,但它们有 3 个问题:

  1. 它们(据我所知)与简单的数据类型一起使用,比如二叉树,我们可以说,我们选择“左”或“右”分支。是否有任何简单的方法可以在上述复杂数据类型上使用它们?
  2. 我认为他们不允许我实现getById具有O(1)时间复杂度的功能,对吗?
  3. 我认为使用 Zippers 创建一些独立的焦点是不可能的。我所说的独立焦点是指焦点,这将允许我们修改数据类型的不同部分,而无需重新计算其他焦点(在 中O(1))。

C++ 的思维方式

在 C++ 中,我们将能够创建指向 AST 节点的指针数组nodePtrs。该函数nodeById将在 中执行O(1),只需访问*(nodePtrs[id]). 因为 C++ 结构是可变的,所以我们可以在没有任何限制的情况下修改它的元素O(1)

4

1 回答 1

2

我认为拉链实际上总是可以实现的,你听说过差异化吗?

好吧,关于getById,我不确定这是个好主意。你可能想要一个像这样的 Haskell 函数getById :: Int -> IO AST,它在数组或其他东西中使用查找。但是由于您以后希望能够修改值(至少在概念上),您想getById返回新修改的 AST 值还是返回存储的第一个 AST 值?这一切都变得有问题。看看您是否可以删除您的 haskell 版本的 ID 可能是个好主意。

我认为你的重点听起来可行。如果我们说这ZAST是 AST 的 zipper 数据类型。那么你也许可以有类似的东西。

makeFocus :: ZAST -> Focus ZAST

type Focus =
  (ZAST -> ZAST) -> -- The modifier of the "below part"
  ZAST ->           -- The new "above part", you have to provide it again as it might have changed
  ZAST              -- The Result

但是,是的,它并不像 C++ 方式那样方便。


总之,我认为您应该退后一步,看看您实际尝试做的事情(AST 优化、发射程序集等)是否可以使用不可变数据结构有效地完成。而不是固执地尝试在 Haskell 中实现可变 C++ 数据结构的相同规范。

于 2013-11-25T10:28:49.490 回答