繁体   English   中英

GHC如何处理核心中的类型类和实例?

[英]How does GHC handle typeclass and instance in core?

我将以下Haskell代码编译为核心:

class FunClass a where
  functionInClass :: a -> ()

data MyData = MyData
data YourData = YourData

instance FunClass MyData where
  functionInClass a = ()
instance FunClass YourData where
  functionInClass a = ()

valueA :: ()
valueA = functionInClass MyData

valueB :: ()
valueB = functionInClass YourData

并获得以下核心绑定(我删除了一些不相关的样板):

 $cfunctionInClass :: MyData -> ()
 [LclId]
 $cfunctionInClass = \ _ [Occ=Dead] -> break<3>() ()

 $fFunClassMyData [InlPrag=INLINE (sat-args=0)] :: FunClass MyData
 $fFunClassMyData
   = $cfunctionInClass
     `cast` (Sym (N:FunClass[0] <MyData>_N)
             :: Coercible (MyData -> ()) (FunClass MyData))

 $cfunctionInClass :: YourData -> ()
 [LclId]
 $cfunctionInClass = \ _ [Occ=Dead] -> break<2>() ()

 $fFunClassYourData [InlPrag=INLINE (sat-args=0)] :: FunClass YourData
 $fFunClassYourData
   = $cfunctionInClass
     `cast` (Sym (N:FunClass[0] <YourData>_N)
             :: Coercible (YourData -> ()) (FunClass YourData))

 valueA :: ()
 [LclIdX]
 valueA
   = break<1>() functionInClass @ MyData $fFunClassMyData MyData

 valueB :: ()
 [LclIdX]
 valueB
   = break<0>()
     functionInClass @ YourData $fFunClassYourData YourData

我的问题是:

  1. 为什么两个cfunctionInClass共享相同的名称? 我们如何区分它们?

  2. cast到底能做什么?

  3. mg_binds ModGuts之外是否有任何与mg_binds ModGuts / instance相关的mg_binds ModGuts

不知道(i)确切的GHC版本,(ii)使用的确切ghc命令行,以及(iii)编译文件的全部内容,很难复制您要查询的核心输出,但是这里有一些答案:

1)生成内核时,您可能提供了-dsuppress-uniques标志,使用了其他暗示它的标志,或者使用了默认版本的GHC的较早版本。 此标志使GHC从核心输出中消除用于创建唯一名称的少量随机后缀。 如果删除标志或添加显式的-dno-suppress-uniques ,则应该看到唯一的名称,例如$cfunctionInClass_r1cH$cfunctionInClass_r1dh

2)Core是一种类型化的语言,并且(广泛地)使用函数cast转换来更改表达式的类型。 请注意,它不会更改表达式本身的内部表示形式,因此只能用于在内存中具有相同内部表示形式的类型之间进行切换。

您会在各处看到使用newtypes代码的newtypes 例如代码:

newtype MyInt = MyInt Int
inc (MyInt n) = MyInt (n + 1)

创建(未优化的)核心:

inc1 :: MyInt -> Int
inc1
  = \ (ds :: MyInt) ->
      + @ Int $fNumInt (ds `cast` (N:MyInt[0] :: MyInt ~R# Int)) (I# 1#)
inc :: MyInt -> MyInt
inc
  = inc1
    `cast` (<MyInt>_R ->_R Sym (N:MyInt[0])
            :: (MyInt -> Int) ~R# (MyInt -> MyInt))

有几个演员。

的方式cast作品中,左手侧`cast`操作者是一个正常的核心术语(例如,可变或其他表达式)表示其类型被改变的值; 右侧是称为“强制”的东西,它是编译器构造的一种证据,用于证明两种类型在表示上是等效的(即,具有相同的内存中表示,因此可以安全地强制)。 例如,在上面的新类型示例中,第一次强制转换的强制是:

N:MyInt[0] :: MyInt ~R# Int

是强制值N:MyInt[0]其类型是MyIntInt的表示相等性( MyInt ~R# )。 (从技术上讲, N:MyInt[0]是强制类型,类型是给定的表示相等性,但是这种区别并不重要。)如果您熟悉Curry-Howard同构,则可以将值视为证明的证明。它们的类型,这是GHC胆量深处的一个例子—值/类型N:MyInt[0]证明了它的类型/种类,即新类型及其内容的表示性相等,从而使演员可以地点。

在您的示例中,强制转换:

$fFunClassMyData [InlPrag=INLINE (sat-args=0)] :: FunClass MyData
$fFunClassMyData
  = $cfunctionInClass
    `cast` (Sym (N:FunClass[0] <MyData>_N)
            :: Coercible (MyData -> ()) (FunClass MyData))

这是一种复杂的说法,即GHC表示类型类的实例字典,该实例类仅具有一个函数,与表示包含该类型的函数的新类型的方式几乎相同,与表示函数值本身的方式相同。 因此,函数值$cfunctionInClass可以直接转换为字典值。

但是,如果您向类型类添加了另一个函数:

class FunClass a where
  functionInClass :: a -> ()
  anotherFunction :: a

这些强制转换将从字典的定义中消失,它们看起来更像您期望的那样:

$fFunClassMyData
$fFunClassMyData = C:FunClass $cfunctionInClass $canotherFunction

重要的是要注意, cast在最终代码中不做任何事情。 一旦核心转换为无类型STG并最终CMM和装配, cast调用优化掉了,因为它们不影响价值,他们只修改编译时间类型,以满足核心typechecker。 因此,除非您正在调试GHC,否则您可能根本不在乎强制转换,因此应考虑不操作。 您可以使用-dsuppress-coercions (由-dsuppress-all-dsuppress-coercions一些细节:

$fFunClassYourData = $cfunctionInClass1 `cast` <Co:3>

并假装x `cast` <Co:xxx>完全等同于x 在你上面的例子中,字典只为类型类的单一实例功能,所以这是真的一样达到强制转换的类型为:

$fFunClassMyData = $cFunctionInClass

3)当然。 附加类和实例信息被存储在mg_tcsmg_insts领域ModGuts分别。 大致来说, mg_binds包含代码生成所需的信息,而mg_tcsmg_insts包含生成接口文件所需的信息。

对GHC编译器代码的有用参考

ghc/compiler/coreSyn/PprCore.hs漂亮打印核心模块。 如果您想知道核心产品的来源,那就是它。 (例如, ppr_expr add_par (Cast expr co) = ...是负责漂亮地打印`cast`运算符的代码。

ghc/compiler/coreSyn/CoreSyn.hs - Expr类型是core的“核心”。 构造函数Cast (Expr b) Coercion表示Cast (Expr b) Coercion

ghc/compiler/types/TycoRep.hs -的定义Coercion在这里。

ghc/compiler/main/HscTypes.hs -的定义ModGuts和字段的“子集” CgGuts用于代码生成和ModIface / ModDetails用于写入接口文件和链接。

ghc/compiler/main/TidyPgm.hs -功能的定义tidyGuts其中, ModGuts信息被分成CgGuts用于代码生成和ModDetails ,的高速缓存版本ModIface编译多个模块时保存在存储器和/或用于产生一个完整的ModIface写入接口文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM