问题描述
在Data.Primitive.SmallArray
中,有函数:
indexSmallArray## :: SmallArray a -> Int -> (#a#)
它以单元素unboxed tuple的形式返回结果。
我的问题是:返回未装箱的元组会得到什么?为什么不简单地返回a
?
我确实获得了多个元素的未装箱元组的有用性。正如Levity Polymorphism论文所说:
最初旨在支持从 函数,未装箱的元组仅仅是用于绑定多个的Haskell语法 价值观在一起。未装箱的元组在运行时根本不存在 [...]在编译过程中,未装箱的元组被完全擦除
解决方法
似乎目标是将索引的工作从“强制” a
本身耦合到WHNF。
如果我们仅返回a
,则评估对WHNF的indexSmallArray##
的调用将执行索引,并且将结果评估到WHNF。
(# a #)
上的模式匹配将执行索引操作(从而释放对隐藏在thunk后面的数组的引用,从而可能使该数组被垃圾回收),但不会强制使用单个组件{{1} }传送到WHNF(据我们所知可能是a
。
在使用类似技术的primop的docs中,我们发现:
primop IndexArrayOp“ indexArray#” GenPrimOp
Array#a-> Int#->(#> a#)
{从不可变数组的指定索引中读取。结果是 包装成 未装箱的一元组;结果本身尚未评估。模式 在元组上进行匹配会强制对数组进行索引 发生但不评估元素本身。这样做 模式匹配立即可用于(1)防止 堆上产生的额外重击和(2)消除 对参数数组的引用,使其成为垃圾 收集起来更及时。}
我想我们可以使用undefined
这样的包装器类型来完成相同的操作,但这会导致不必要的堆分配,而未装箱的元组不会发生这种情况。