因此,我有一个具有单个严格字段的​​存在数据类型:

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的总大小。

10-06 10:32