首页 > 解决方案 > 了解单态与多态核心表达式

问题描述

我想了解如何将简单的算术表达式编译到 GHC 9.0.1 Core

为此,我隔离了相同的声明,

f = \x y -> sqrt x + y

并将其编译为两种不同的类型:

f :: Double -> Double -> Double

f :: Floating a => a -> a -> a

导致这些非常不同的野兽:

\ (x [Dmd=<S,1*U(U)>] :: Double) (y [Dmd=<S,1*U(U)>] :: Double) ->
  case x of { D# x ->
  case y of { D# y -> D# (+## (sqrtDouble# x) y) }
  }

在单态的情况下和

\ (@a)
  ($dFloating_a22t [Dmd=<S(S(S(C(C(S))LLLLLL)LLL)LLLLLLLLLLLLLLLLLLLLLL),U(1*U(1*U(1*C1(C1(U)),A,A,A,A,A,A),A,A,A),A,A,A,1*C1(U),A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A,A)>]
     :: Floating a)
  (eta_B0 :: a)
  (eta_B1 :: a) ->
  + @a
    ($p1Fractional @a ($p1Floating @a $dFloating_a22t))
    (sqrt @a $dFloating_a22t eta_B0)
    eta_B1

在多态之一。

除了需要单独提出问题的需求/严格性注释(这些Dmd=...东西)之外,我很想了解这两个结果表达式的不同形状。在单态情况下,我们进行了嵌套大小写匹配,但在另一种情况下,我们只看到使用类型变量 ( @a) 和约束 ($p1Fractional等)注释的运算符。

我想我应该补充一点,上面的输出是通过在预先存在的 CoreToDo 列表的最后运行的自定义插件传递获得的,所以在脱糖等之后(这就是我对这个主题的全部了解)

是否存在这两个编译版本在结构上相同的 GHC 阶段?

标签: haskellghc

解决方案


在内部,aFloat是一个数据构造函数,其中一个字段包含Float#底层机器格式的原语(因此是 32 位字)。

data Float = MkFloat Float#

这是一个加框表示,因此 aFloat也可能是一个 thunk。表达式的作用是case评估任何 thunk 然后访问底层机器Float#

因此,您的函数Float -> Float -> Float在简化后编译为与参数匹配的函数,并对基础值执行原始操作。


类型类被编译成字典。

class Floating a where
  sqrt :: a -> a
  ...

-- becomes a record --

data Floating a = MkFloating {
  sqrt :: a -> a,
  ... }

多态函数成为字典传递函数

Floating a => a -> a -> a
-- becomes --
Floating a -> a -> a -> a

方法调用成为字段访问:

sqrt x
-- becomes --
sqrt floatingDict x

-- where floatingDict :: Floating a is constructed from dictionary parameters in scope and from instances (which are compiled to dictionaries or functions on dictionaries)

(注意:这在某种程度上是特定于 GHC 的,其他编译器虽然很少见,但可能会做不同的事情。)


是否存在这两个编译版本在结构上相同的 GHC 阶段?

不,他们为什么会这样?


推荐阅读