这是一个Haskell问题,但我也对其他语言的答案感兴趣。有没有办法自动翻译纯函数代码,编写为处理列表或不可变数组而不进行任何破坏性更新,代码使用可变数组来提高效率?
在Haskell中,生成的代码将在ST
monad中运行(在这种情况下,它将全部包含在runST
或runSTArray
中)或IO
monad中,我认为。
我最感兴趣的是适用于任何元素类型的通用解决方案。
我以为我以前见过这个,但我不记得在哪里。如果它还不存在,我有兴趣创建它。
答案 0 :(得分:4)
使用破坏性更新实现功能语言是一种内存管理优化。如果将不再使用旧值,则可以安全地重用旧内存来保存新值。检测到不再使用某个值是一个难题,这就是为什么仍然需要手动管理重用的原因。
Linear type inference和唯一性类型推断发现了一些有用的信息。这些分析发现了仅包含某个对象的变量。在最后一次使用该变量之后,要么将对象转移到其他位置,要么可以重用该对象来保存新值。
多种语言(包括Sisal和SAC)尝试重用旧数组内存来保存新数组。在SAC中,程序首先转换为使用显式内存管理(特别是引用计数),然后优化内存管理代码。
答案 1 :(得分:0)
你说“列表或不可变数组”,但这些实际上是两个非常不同的东西,并且在许多情况下,当与可变数组一起使用时,自然适合列表的算法不会更快(并且可能更慢)。
例如,考虑一个由三部分组成的算法:从一些输入构造一个列表,通过组合相邻元素来转换列表,然后按一些标准过滤列表。在每个步骤中完全生成新列表的天真方法确实是低效的;在每个步骤中更新到位的可变阵列将是一种改进。但更好的是观察到同时只需要有限数量的元素并且算法的线性特性与列表的线性结构相匹配,这意味着所有三个步骤可以合并在一起并且中间列表完全消除。如果用于构造列表的初始输入和过滤结果明显小于中间列表,则可以通过避免额外分配来节省大量开销,而不是使用刚过滤掉的元素填充可变数组后来无论如何。
当对数组进行大量零散的随机访问更新时,可变数组最有用,没有明显的线性结构。当使用Haskell的不可变数组时,在很多情况下,这可以使用accum
中的Data.Array
函数来表示,我相信它已经使用ST
实现了。
简而言之,许多简单案例要么具有更好的优化,要么已经处理好。
编辑:我注意到这个答案没有发表评论,我很好奇为什么。感谢您的反馈,我想知道我是否说了些蠢话。