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

ram*_*ion 5 haskell existential-type strictness

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

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

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

? p = (0, '\0') :: (Int, Char)
? q = Uncurry p
? unsafeSizeof p
10
? unsafeSizeof q
10
Run Code Online (Sandbox Code Playgroud)

所以它看起来像是Uncurry一种表现形式,newtype仅在编译时使用.

这对我来说很有意义,因为平等断言不需要提供字典.

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

And*_*ács 6

data永远不会变成newtype.Uncurry确实添加了一个新的闭包,~实际上也是一个字典的指针,从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)
Run Code Online (Sandbox Code Playgroud)

但请注意,unsafeSizeof只给出了最顶部封闭的大小.因此,任何盒装元组的关闭规模将24,这与关闭大小一致Uncurry t,因为Uncurry有一个信息指针,对于无用的指针~,并为元组领域的指针.这种巧合也适用于之前的马车unsafeSizeof实施.但总的大小Uncurry t要大于t.


K. *_*uhr 5

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

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

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

{-# 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, '\0')

r :: Uncurry (,) '(Int, Char)
r = Uncurry (1, '\1')
Run Code Online (Sandbox Code Playgroud)

那么顶级q闭包的内存占用量如下:

q_closure:
    .quad   Uncurry_static_info
    .quad   $s$WUncurry_$d~~_closure+1
    .quad   q1_closure+1
    .quad   3
Run Code Online (Sandbox Code Playgroud)

注意,.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
Run Code Online (Sandbox Code Playgroud)

另外24个字节.

q2q3封闭件盒装IntChar等占用两个四芯导线(16个字节)的每个.因此,q总共需要10个四边形或80个字节.(我将其r作为完整性检查包括在内,以确保我没有错误地识别任何共享信息.)

p本身元组将具有内存占用相当于q1_closure,所以7个四边形或56个字节.