具有单一严格字段的​​存在性数据类型

所以我有一个严格的字段存在的数据类型:

data Uncurry (a :: i -> j -> *) (z :: (i,j)) =
  forall x y. z ~ '(x,y) => Uncurry !(a x y) 

使用unsafeSizeof (从这个答案中窃取)的实验使我相信它可以是零内存开销:

λ p = (0, '') :: (Int, Char)
λ q = Uncurry p
λ unsafeSizeof p
10
λ unsafeSizeof q
10

所以好像Uncurry是有点像个newtype ,只有在编译时使用。

这对我来说很有意义,因为平等主张并不需要一本字典。

这是一个有效的解释吗? 我是否有任何来自GHC(或Haskell报告)的保证,还是我只是运气好?


data永远不会转化为newtypeUncurry确实增加了一个新的闭包,并且~字典的指针实际上也是在GHC 8.0.2中加入的。 因此, Uncurry用三个词结束。

unsafeSizeof不正确,因为Array#以字的形式存储它的大小,而ByteArray#以字节存储它的大小,所以sizeofByteArray# (unsafeCoerce# ptrs)返回的是单词的数量而不是预期的字节数。 正确的版本在64位系统上看起来像这样:

unsafeSizeof :: a -> Int
unsafeSizeof !a =
  case unpackClosure# a of
    (# x, ptrs, nptrs #) ->
      I# (8# +# sizeofArray# prts *# 8# +# sizeofByteArray# nptrs)

但请注意, unsafeSizeof只会给我们顶部封闭的大小。 因此,任何盒装元组的封闭大小将为24 ,这与Uncurry t的封闭大小一致,因为Uncurry具有信息指针,用于~的无用指针和用于元组字段的指针。 这个巧合也适用于之前的bug unsafeSizeof实现。 但Uncurry t的总大小大于t


编辑修复一些细节:四字节为8字节并解释静态链接字段。

我认为unsafeSizeOf不准确,你误解了它的输出。 请注意,它仅用于显示顶级闭包的内存使用情况,而不是该对象的总空间使用情况。 我认为,你所看到的是q除了元组p之外还需要10个字节(而除了装箱的Char和盒装Int之外, p需要10个字节)。 此外,我的测试表明,顶级构造函数实际上每个需要24个字节(在64位架构上),即使unsafeSizeOf为我报告10。

特别是,如果我使用GHC 8.0.2编译以下测试程序并使用stack ghc -- -fforce-recomp -ddump-asm -dsuppress-all -O2 ZeroMemory.hs

{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}

module ZeroMemory where

data Uncurry (a :: i -> j -> *) (z :: (i, j)) =
  forall x y . z ~ '(x,y) => Uncurry !(a x y)

q :: Uncurry (,) '(Int, Char)
q = Uncurry (0, '')

r :: Uncurry (,) '(Int, Char)
r = Uncurry (1, '1')

那么顶级q闭包的内存占用情况如下所示:

q_closure:
    .quad   Uncurry_static_info
    .quad   $s$WUncurry_$d~~_closure+1
    .quad   q1_closure+1
    .quad   3

请注意,这里的每个.quad实际上是8个字节; 这是一个旧式16位“字”的“四元组”。 我相信这里的最终quad值为3,它是GHC实现注释中描述的“静态链接字段”,因此不适用于“典型”堆分配对象。

因此,忽略这个最后一个字段,顶级q闭包的总大小是24个字节,它是指代表包含的元组的q1_closure

q1_closure:
    .quad   (,)_static_info
    .quad   q3_closure+1
    .quad   q2_closure+1
    .quad   3

另外24个字节。

q2q3闭包是盒装IntChar ,因此每个占用两个四元组(16字节)。 所以, q总共需要10个四元组,或80个字节。 (我包括r作为一个完整的检查,以确保我没有错误识别任何共享信息。)

一个p元组本身会有一个相当于q1_closure的内存空间,所以有7个四元组或56个字节。

链接地址: http://www.djcxy.com/p/43453.html

上一篇: Existential data types with a single strict field

下一篇: GHC existentially quantified singleton