Haskell 如何找到GHC';数据类型的内存表示形式?

Haskell 如何找到GHC';数据类型的内存表示形式?,haskell,ghc,Haskell,Ghc,最近,诸如的博客文章解释了如何对常用容器类型的空间复杂性进行推理。现在我面临的问题是,如何真正“看到”我的GHC版本为奇怪的数据类型(构造函数)选择了哪种内存布局(取决于编译标志和目标体系结构),例如 在C中有sizeof和offsetof操作符,它允许我“查看”为Cstruct的字段选择的大小和对齐方式 我试着查看GHC Core,希望在那里找到一些提示,但我不知道要查找什么。谁能给我指出正确的方向吗? (以下适用于GHC,其他编译器可能使用不同的存储约定) 经验法则:一个构造器的头需要一个单

最近,诸如的博客文章解释了如何对常用容器类型的空间复杂性进行推理。现在我面临的问题是,如何真正“看到”我的GHC版本为奇怪的数据类型(构造函数)选择了哪种内存布局(取决于编译标志和目标体系结构),例如

在C中有
sizeof
offsetof
操作符,它允许我“查看”为C
struct
的字段选择的大小和对齐方式

我试着查看GHC Core,希望在那里找到一些提示,但我不知道要查找什么。谁能给我指出正确的方向吗?

(以下适用于GHC,其他编译器可能使用不同的存储约定)

经验法则:一个构造器的头需要一个单词,每个字段需要一个单词。例外:没有字段的构造函数(如Nothing或True)不占用空间,因为GHC创建这些构造函数的单个实例,并在所有用户之间共享它

一个字在32位机器上是4字节,在64位机器上是8字节

例如

data Uno = Uno a
data Due = Due a b
一个Uno需要2个单词,一个到期需要3个单词


此外,我相信可以编写一个haskell函数,它执行与
sizeof
offsetof
相同的任务。我的第一个想法是使用这个函数,因为Simon Marlow:

{-# LANGUAGE MagicHash,UnboxedTuples #-}
module Size where

import GHC.Exts
import Foreign

unsafeSizeof :: a -> Int
unsafeSizeof a =
  case unpackClosure# a of
    (# x, ptrs, nptrs #) ->
      sizeOf (undefined::Int) + -- one word for the header
        I# (sizeofByteArray# (unsafeCoerce# ptrs)
             +# sizeofByteArray# nptrs)
使用它:

Prelude> :!ghc -c Size.hs

Size.hs:15:18:
    Warning: Ignoring unusable UNPACK pragma on the
             third argument of `BitVec257'
    In the definition of data constructor `BitVec257'
    In the data type declaration for `BitVec257'
Prelude Size> unsafeSizeof $! BitVec514 (BitVec257 1 2 True 3 4) (BitVec257 1 2 True 3 4)
74
(请注意,GHC告诉您它不能取消装箱
Bool
,因为它是一种求和类型。)

上述函数声明您的数据类型在64位机器上使用74字节。我觉得很难相信。我希望数据类型使用11个字=88字节,每个字段一个字。即使是
Bool
s也需要一个单词,因为它们是指向(静态分配的)构造函数的指针。我不太清楚这里发生了什么


至于对齐,我认为每个字段都应该是单词对齐。

哦,thx,我还没有看到其他问题。但实际上,我对“经验法则”不太感兴趣,我希望能够解码实际的内存量。我假设GHC必须以某种方式存储使用过的内存布局,以便能够相应地整理数据,可能是存储在那些
.hi
文件中的实际内存布局?这种“经验法则”在多态情况下实际上是准确的。如果你开始{-#解包{-}或处理类似字段{-#,它只会变得更复杂。有些字段可能需要多个插槽来存储,比如32位平台上的Double#或Word64#。你的动机是什么?纯粹的好奇心,或者你正试图与另一种语言交流,或者其他什么?是的,主要是好奇心。我希望能够验证GHC是否真的做到了我期望/假设的事情。。。或者我是否需要修正我的假设…:-)啊,我认为这个函数有一个bug,因为我们改变了ByteArray的表示形式(它现在的长度是字节而不是单词),所以
sizeOfByteArray
不会乘以单词大小。您需要将第一个
sizeOFByteArray#
的结果乘以单词大小。顺便问一下,
ptrs
nptrs
实际上代表什么?
Prelude> :!ghc -c Size.hs

Size.hs:15:18:
    Warning: Ignoring unusable UNPACK pragma on the
             third argument of `BitVec257'
    In the definition of data constructor `BitVec257'
    In the data type declaration for `BitVec257'
Prelude Size> unsafeSizeof $! BitVec514 (BitVec257 1 2 True 3 4) (BitVec257 1 2 True 3 4)
74