我为 Core Haskell 编写了一个自定义的漂亮打印机,以便更好地研究 Core 的结构。这台漂亮打印机的要点是,它需要核心模块并在输出中包含数据构造函数,默认情况下Outputable
执行好像不行。
这是我运行漂亮打印机的模块的代码:
module Bar2 where
add :: Int -> Int -> Int
add a b = a + b
add2 a b = a + b
这是漂亮的打印机输出:
------------------------------- Module Metadata --------------------------------
Module { "main" :: modulePackageId, "Bar2" :: moduleName }
-------------------------------- Type Bindings ---------------------------------
[r0 :-> Identifier ‘add’, rjH :-> Identifier ‘add2’]
-------------------------------- Core Bindings ---------------------------------
NonRec (Id "add2")
(Lam (TyVar "a")
(Lam (Id "$dNum")
(Lam (Id "a1")
(Lam (Id "b")
(App (App (App (App (Var (Id "+"))
(Type (TyVar (TyVar "a"))))
(Var (Id "$dNum")))
(Var (Id "a1")))
(Var (Id "b")))))))
NonRec (Id "add")
(Lam (Id "a")
(Lam (Id "b")
(App (App (App (App (Var (Id "+"))
(Type (TyConApp (Int) [])))
(Var (Id "$fNumInt")))
(Var (Id "a")))
(Var (Id "b")))))
--------------------------------- Safe Haskell ---------------------------------
Safe
------------------------------------- End --------------------------------------
让我感到困惑的是,在这两种情况下,Core 似乎都将类型变量或类型构造函数应用于+
功能,以及一些$dNum
or $fNumInt
在接受论点之前。
For the add
函数,类型也明确给出,而add2
留给编译器推断。这似乎也会影响 lambda 函数链求值所需的参数数量,其中add
需要 2 同时add2
要求 4.
这是什么意思呢?
核心就差不多了SystemF(从技术上来说SystemFC)。在 SystemF 中,类型变量也需要作为函数的参数。在你的例子中,Haskell 推断
add2 :: Num a => a -> a -> a
add2 a b = a + b
这解释了TyVar "a"
论证add2
.
此外,Haskell 必须找到一种方法来分派到“正确的”集合Num
函数取决于参数的类型a
and b
是。它通过为每个类型类约束提供一个字典参数来实现这一点。这就是Id $dNum
争论。如果是add
, Haskell 已经知道哪个字典合适(+)
可以找到函数,因为它知道它知道操作正在进行Int
(所以不需要传入:它只是$fNumInt
).
本质上,在幕后发生的事情是 Haskell 为每个类型类创建一个记录data $d<Class> = ...
字段是类型类内的函数。然后,对于每个实例,它会生成另一个实例$f<Class><Type> :: $d<Class>
. 这里有更详细的解释
这是另一个描述核心相关事物的优秀答案。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)