[英]How to compile Haskell into the untyped lambda calculus (or GHC core)?
I'm looking for ways how to convert a simple Haskell program (no imported libraries, just data types and pure functions) into a term of the untyped lambda calculus. 我正在寻找如何将简单的Haskell程序(没有导入的库,只是数据类型和纯函数)转换为无类型lambda演算的术语。 A promising approach seems to be to use GHC API to compile a program into GHC core , which can be then converted into the untyped lambda calculus.
一种有希望的方法似乎是使用GHC API将程序编译成GHC核心 ,然后可以将其转换为无类型的lambda演算。
How to use GHC API to load a Haskell program and compile it into Core? 如何使用GHC API加载Haskell程序并将其编译为Core?
From the GHC
module documentation in the ghc docs: 从ghc文档中的
GHC
模块文档 :
compileToCoreModule :: GhcMonad m => FilePath -> m CoreModule
This is the way to get access to the Core bindings corresponding to a module.
这是访问与模块对应的Core绑定的方法。
compileToCore
parses, typechecks, and desugars the module, then returns the resulting Core module (consisting of the module name, type declarations, and function declarations) if successful.compileToCore
解析,类型检查和desugars模块,然后返回生成的Core模块(包括模块名称,类型声明和函数声明),如果成功的话。
compileToCoreSimplified :: GhcMonad m => FilePath -> m CoreModule
Like
compileToCoreModule
, but invokes the simplifier, so as to return simplified and tidied Core.像
compileToCoreModule
一样,但是调用简化器,以便返回简化和整理的Core。
I found this by looking through the list of GHC
modules, noticing the Desugar
module, noticing ModGuts
in the result of deSugar
, downloading all of the documentation, and searching the text for ModGuts
. 我通过查看
GHC
模块列表,注意Desugar
模块,注意ModGuts
结果中的deSugar
,下载所有文档以及搜索ModGuts
文本来ModGuts
。
Our example will compile a simple module so we can see what the core looks like. 我们的示例将编译一个简单的模块,以便我们可以看到核心的样子。 It uses ghc-paths to provide the location of the ghc libs directory.
它使用ghc-paths来提供ghc libs目录的位置。 The core will be represented in memory by a
CoreModule
containing a list of CoreBind
s . 核心将由包含
CoreBind
列表的CoreModule
在内存中表示。 We can't dump the AST directly because there aren't Show
instances for the AST described in CoreSyn
, however the Outputable
instance for CoreModule
will pretty-print the core so we can see that we compiled to core. 我们不能直接转储AST,因为
CoreSyn
中没有描述AST的Show
实例,但是CoreModule
的Outputable
实例将完全打印核心,因此我们可以看到我们编译为核心。
import GHC
import DynFlags
import Outputable (Outputable, showPpr)
import qualified GHC.Paths as Paths
import Data.Functor
runGhc'
takes care of all the setup needed for compiling to core a module with no import
s and no TemplateHaskell
. runGhc'
负责编译核心模块所需的所有设置,没有import
和没有TemplateHaskell
。 We completely turn off the linker with NoLink
and tell the compiler to produce nothing with HscNothing
. 我们用
NoLink
完全关闭了链接器并告诉编译器什么都不生成HscNothing
。
runGhc' :: Ghc a -> IO a
runGhc' ga = do
runGhc (Just Paths.libdir) $ do
dflags <- getDynFlags
let dflags2 = dflags { ghcLink = NoLink
, hscTarget = HscNothing
}
setSessionDynFlags dflags2
ga
Compiling a module to core consists of setting the target with guessTarget
and addTarget
, optionally loading dependencies with load
, building the module graph with depanel
, find
ing the correct ModSummary
in the module graph, parsing the module with parseModule
, type checking it with typecheckModule
, desugarring it with desugarModule
, converting it to ModGuts
with coreModule
from the DesugaredMod
instance for the result of desugarring, and extracting the core from the ModGuts
. 编译模块到核心包括设置目标用的
guessTarget
和addTarget
,任选加载与依赖load
,与构建模块图表depanel
, find
荷兰国际集团的正确ModSummary
在模块图形,解析与所述模块parseModule
,类型与检查它typecheckModule
,使用desugarModule对其进行desugarModule
,使用来自DesugaredMod
实例的DesugaredMod
将其转换为ModGuts
以coreModule
DesugaredMod
的结果,并从ModGuts
提取核心。 All of this is wrapped up in a nice package by compileToCoreModule
. 所有这些都由
compileToCoreModule
包装在一个很好的包中。
compileExample :: Ghc CoreModule
compileExample = compileToCoreModule "prettyPrint2dList.hs"
Our whole example program will output the core with showPpr
. 我们的整个示例程序将使用
showPpr
输出核心。
showPpr' :: (Functor m, Outputable a, HasDynFlags m) => a -> m String
showPpr' a = (flip showPpr) a <$> getDynFlags
main = runGhc' (compileExample >>= showPpr') >>= putStrLn
Compiling the above example requires the -package ghc
flag to expose the normally hidden ghc api package. 编译上面的示例需要
-package ghc
标志来公开通常隐藏的ghc api包。
The example module we'll compile to core, "prettyPrint2dList.hs"
, contains a data type and a bit of code that uses functions from the prelude. 我们将编译为核心的示例模块
"prettyPrint2dList.hs"
包含一个数据类型和一些使用前奏函数的代码。
data X = Y | Z
deriving (Eq, Show)
type R = [X]
type W = [R]
example = map (\x -> take x (cycle [Y, Z])) [0..]
main = undefined
Which produces a slew of pretty-printed core. 这产生了大量漂亮的印刷核心。
%module main:Main (Safe-Inferred) [01D :-> Identifier `:Main.main',
a1f2 :-> Identifier `$c==', a1f5 :-> Identifier `$c/=',
a1fb :-> Identifier `$cshowsPrec', a1fh :-> Identifier `$cshow',
a1fk :-> Identifier `$cshowList',
r0 :-> Identifier `Main.$fShowX', r1 :-> Identifier `Main.$fEqX',
r2 :-> Type constructor `Main.R',
r3 :-> Type constructor `Main.X', r4 :-> Identifier `Main.main',
rqS :-> Type constructor `Main.W',
rrS :-> Data constructor `Main.Y', rrV :-> Identifier `Main.Y',
rrW :-> Data constructor `Main.Z', rrX :-> Identifier `Main.Z',
rL2 :-> Identifier `Main.example']
Main.example :: [[Main.X]]
[LclIdX, Str=DmdType]
Main.example =
GHC.Base.map
@ GHC.Types.Int
@ [Main.X]
(\ (x :: GHC.Types.Int) ->
GHC.List.take
@ Main.X
x
(GHC.List.cycle
@ Main.X
(GHC.Types.:
@ Main.X
Main.Y
(GHC.Types.: @ Main.X Main.Z (GHC.Types.[] @ Main.X)))))
(GHC.Enum.enumFrom
@ GHC.Types.Int GHC.Enum.$fEnumInt (GHC.Types.I# 0))
Main.main :: forall t. t
[LclIdX, Str=DmdType]
Main.main = GHC.Err.undefined
$cshowsPrec :: GHC.Types.Int -> Main.X -> GHC.Show.ShowS
[LclId, Str=DmdType]
$cshowsPrec =
\ _ [Occ=Dead] (ds_d1gG :: Main.X) ->
case ds_d1gG of _ [Occ=Dead] {
Main.Y ->
GHC.Show.showString
(GHC.Types.:
@ GHC.Types.Char
(GHC.Types.C# 'Y')
(GHC.Types.[] @ GHC.Types.Char));
Main.Z ->
GHC.Show.showString
(GHC.Types.:
@ GHC.Types.Char
(GHC.Types.C# 'Z')
(GHC.Types.[] @ GHC.Types.Char))
}
Main.$fShowX [InlPrag=[ALWAYS] CONLIKE] :: GHC.Show.Show Main.X
[LclIdX[DFunId],
Str=DmdType,
Unf=DFun: \ ->
GHC.Show.D:Show TYPE Main.X $cshowsPrec $cshow $cshowList]
Main.$fShowX =
GHC.Show.D:Show @ Main.X $cshowsPrec $cshow $cshowList;
$cshowList [Occ=LoopBreaker] :: [Main.X] -> GHC.Show.ShowS
[LclId, Str=DmdType]
$cshowList =
GHC.Show.showList__
@ Main.X
(GHC.Show.showsPrec @ Main.X Main.$fShowX (GHC.Types.I# 0));
$cshow [Occ=LoopBreaker] :: Main.X -> GHC.Base.String
[LclId, Str=DmdType]
$cshow = GHC.Show.$dmshow @ Main.X Main.$fShowX;
$c== :: Main.X -> Main.X -> GHC.Types.Bool
[LclId, Str=DmdType]
$c== =
\ (ds_d1gB :: Main.X) (ds_d1gC :: Main.X) ->
let {
fail_d1gD :: GHC.Prim.Void# -> GHC.Types.Bool
[LclId, Str=DmdType]
fail_d1gD = \ _ [Occ=Dead, OS=OneShot] -> GHC.Types.False } in
case ds_d1gB of _ [Occ=Dead] {
Main.Y ->
case ds_d1gC of _ [Occ=Dead] {
__DEFAULT -> fail_d1gD GHC.Prim.void#;
Main.Y -> GHC.Types.True
};
Main.Z ->
case ds_d1gC of _ [Occ=Dead] {
__DEFAULT -> fail_d1gD GHC.Prim.void#;
Main.Z -> GHC.Types.True
}
}
Main.$fEqX [InlPrag=[ALWAYS] CONLIKE] :: GHC.Classes.Eq Main.X
[LclIdX[DFunId],
Str=DmdType,
Unf=DFun: \ -> GHC.Classes.D:Eq TYPE Main.X $c== $c/=]
Main.$fEqX = GHC.Classes.D:Eq @ Main.X $c== $c/=;
$c/= [Occ=LoopBreaker] :: Main.X -> Main.X -> GHC.Types.Bool
[LclId, Str=DmdType]
$c/= =
\ (a :: Main.X) (b :: Main.X) ->
GHC.Classes.not (GHC.Classes.== @ Main.X Main.$fEqX a b);
:Main.main :: GHC.Types.IO GHC.Prim.Any
[LclIdX, Str=DmdType]
:Main.main =
GHC.TopHandler.runMainIO
@ GHC.Prim.Any (Main.main @ (GHC.Types.IO GHC.Prim.Any))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.