【发布时间】:2023-04-06 07:01:01
【问题描述】:
GHC 是否在将 sum 类型传递给函数时对其进行解包?例如,假设我们有以下类型:
data Foo
= Foo1 {-# UNPACK #-} !Int {-# UNPACK #-} !Word
| Foo2 {-# UNPACK #-} !Int
| Foo3 {-# UNPACK #-} !Word
然后我在其Foo 参数中定义了一个严格的函数:
consumeFoo :: Foo -> Int
consumeFoo x = case x of ...
在运行时,当我调用consumeFoo 时,我会发生什么? GHC calling convention 是在寄存器中传递参数(或者一旦有太多就在堆栈上)。我可以看到参数传递的两种方式:
- 指向堆上
Foo的指针作为一个参数传入。 - 使用
Foo的三个参数表示,一个参数表示使用的数据构造函数,另外两个表示数据构造函数中可能的Int和Word值。
我更喜欢第二种表示,但我不知道它是否真的发生了。我知道UnpackedSumTypes 登陆 GHC 8.2,但不清楚它是否符合我的要求。如果我把函数写成:
consumeFooAlt :: (# (# Int#, Word# #) | Int# | Word# #) -> Int
然后我希望评估 (2) 会发生什么。解压总和页面的Unpacking section 表明我也可以这样做:
data Wrap = Wrap {-# UNPACK #-} !Foo
consumeFooAlt2 :: Wrap -> Int
我认为这也应该有我想要的表示。
所以我的问题是,如果不使用包装器类型或未打包的原始总和,当我将总和作为参数传递给函数时,如何保证总和被解压到寄存器(或堆栈上)?如果可能的话,是 GHC 8.0 已经可以做到的事情,还是只有 GHC 8.2 才有的事情?
【问题讨论】: