【问题标题】:Understanding space leak with Arrow使用 Arrow 了解空间泄漏
【发布时间】:2019-08-22 09:37:30
【问题描述】:
我很难理解 Hudak 的论文“用箭头堵塞空间泄漏”中的空间泄漏
https://www.sciencedirect.com/science/article/pii/S1571066107005919.
1) O(n) 空间复杂度到底是什么意思?根据输入大小分配的总内存?一路上的垃圾收集呢?
2) 如果 1) 中的定义成立,那么如何在第 34 页中说如果 dt 是常量,则信号类型类似于列表类型并在常量空间中运行?是不是integralC还是每一步创建1个空间单位,一共n个单位,也就是O(n)?
3) 我完全不明白为什么时间复杂度是 O(n^2)。我确实对需要评估的内容有所了解(下图中的 i',i'',i'''),但是 O(n^2) 怎么样?
该图像表示我以 lambda 图形表示法绘制的评估步骤。每个步骤都将其结构添加到整体范围中,而不是替换其中的任何内容。 Square 表示指针,例如步骤 2 中的 square(i') 表示步骤 1 中的 i' 块。
【问题讨论】:
标签:
haskell
functional-programming
arrows
【解决方案1】:
我只是简单地看了一眼论文,但会尽力而为。
像往常一样,空间复杂度意味着我们需要在某个时间点同时在内存中存储那么多“东西”。 GC 说我们可以从不再需要的变量中恢复内存,但是在这里我们需要记住O(n) 的东西,内存还不能恢复,因为我们(可能)仍然需要访问它的任何部分。您可以将其视为重用内存(通过例如 GC)会增加时间但不会增加空间复杂性。这里,n 通过提供 n 个时间步长 (dts) 来计算第 n 个值。
如果dt 是常量,那么我们有C' a = (a, C' a) 而不是C a = (a, dt -> C a) 的类型,它只是一个(非空)列表。论文的重点是任何一种类型都可以在恒定空间中运行,但如果它与列表同构,那么这是一个已解决的问题。要了解为什么在每一步创建一个新值可能是常量内存,请考虑对(iterate f)!!n 的可能评估,我们只存储 x,然后用f (x) 覆盖它,然后用f (f (x)) 覆盖它,依此类推,直到我们有f^n(x),但只使用这一个内存单元来存储我们的值(从技术上讲,第二个单元可以迭代到n)。
让我们考虑一个非常简单的评估示例,给出这些不同的复杂性。假设我们正在从某个种子生成一个列表,其中每个项目是所有先前项目的总和。为了计算下一个项目,我们可以将列表的初始部分 p 的全部内容保存在内存中 (O(Len(p))) 并将其相加 (O(Len(p))),得到总内存 O(n) 和运行时间 O(n^2) to retrieve then` th 元素 - 或者我们可以观察到这实际上与将前一项加倍相同,允许我们使用恒定的内存和线性时间。我认为给出的类比部分很有帮助——你能机械地写出前几个值的后继值,看看这两种不同的评估策略是如何在所需的步骤上迅速分歧的吗?