因此,我有一个具有单个严格字段的存在数据类型:
data Uncurry (a :: i -> j -> *) (z :: (i,j)) =
forall x y. z ~ '(x,y) => Uncurry !(a x y)
使用
unsafeSizeof
(从this answer窃取)进行的实验使我相信它的内存开销可以为零:λ p = (0, '\0') :: (Int, Char)
λ q = Uncurry p
λ unsafeSizeof p
10
λ unsafeSizeof q
10
因此,似乎
Uncurry
有点像newtype
,仅在编译时使用。这对我来说很有意义,因为等价断言不需要携带字典。
这是有效的解释吗?我是否可以从GHC(或Haskell报告)中获得任何保证,还是只是运气好?
最佳答案
data
永远不会转换为newtype
。从GHC 8.0.2开始,Uncurry
确实添加了一个新的闭包,并且实际上也附带了~
字典的指针。因此,Uncurry
具有三个单词的闭包。unsafeSizeof
不正确,因为Array#
以字为单位存储其大小,而ByteArray#
以字节为单位存储其大小,因此sizeofByteArray# (unsafeCoerce# ptrs)
返回字数,而不是预期的字节数。在64位系统上,正确的版本应如下所示:
unsafeSizeof :: a -> Int
unsafeSizeof !a =
case unpackClosure# a of
(# x, ptrs, nptrs #) ->
I# (8# +# sizeofArray# nptrs *# 8# +# sizeofByteArray# ptrs)
但是请注意,unsafeSizeof
仅给我们最大的闭合大小。因此,任何盒装元组的闭包大小将为24
,这与Uncurry t
的闭包大小一致,因为Uncurry
具有信息指针,~
的无用指针和元组字段的指针。这种巧合也适用于先前的错误unsafeSizeof
实现。但是Uncurry t
的总大小大于t
的总大小。