在Haskell中表达逻辑常量

时间:2016-04-21 07:48:16

标签: haskell data-structures const

数据结构具有变异和非变异操作。例如,字典插入可以更改其基础数据结构的状态,但查找通常不会。

一些数据结构改变了它们的内部结构 - 即使在逻辑上非变异操作 - 但是以不改变可观察状态的方式。例如,splay tree在查找时将元素移向根,并且move-to-front list在查找时将元素移向头部。从逻辑上讲,这组密钥没有改变。

在C ++中,可以通过定义具有const方法但mutable数据成员的数据结构来实现。有没有办法在Haskell中这样做?我唯一能想到的是

setContains :: Set k -> k -> (Set k, Bool)

但这很难看,因为底层数据结构会改变界面。

1 个答案:

答案 0 :(得分:6)

如果不使用不安全的原语,就无法实现这种低级优化,因此允许从纯代码中突变数据结构。

首先,请注意,在GHC运行时,纯代码 修改数据结构 - 通过评估它们。 E.g。

x = (3+2, 4+5)
main = print (fst x) >>> print (fst x)

在GHC中,第一个print调用实际上重写 x(5, 4+5),用结果重写其第一个组件。这样,第二个print不必再次执行添加。 当然,这种重写永远不会改变x的语义,因此它是一种特殊的,#34;安全的#34;一种突变。

有时这还不足以实现一些低级优化,例如问题中描述的优化。然后,不安全的原语是唯一的选择。

我相信这种技术的典型例子是Data.Array.Diff。这是一个不可变的数组数据结构,具有恒定的时间访问和更新(!)。在引擎盖下,有一个可变数组,其中必须执行更新。由于这会严重破坏对 immutable 数组的旧引用,因此这些引用也指向(可变)" changelog"在更新之前存储旧值。因此,我们得到了一种"版本控制" system:最后一个版本很快,旧版本变得越来越慢。 从外面看,只能观察到纯粹的行为;在里面,发生了很多变异。

该实现使用MVar来阻止并发访问,以避免OP在上面的注释中描述的多线程问题。

让我再次强调,这种技巧在Haskell中绝对被认为是单一的。在日常编程中,这是编写好的,可读的,可靠的Haskell代码的方式。