如何将Haskell编译成非类型化的lambda演算(或GHC核心)?
我正在寻找如何将一个简单的Haskell程序(并没有导入库,只有数据类型和纯函数)转换成一个非类型化的lambda演算术语的方法。一种很有希望的方法似乎是将程序编译成,然后将其转换为非类型化的lambda演算 如何使用GHC API加载Haskell程序并将其编译成Core?来自GHC文档中的:如何将Haskell编译成非类型化的lambda演算(或GHC核心)?,haskell,lambda-calculus,ghc-api,Haskell,Lambda Calculus,Ghc Api,我正在寻找如何将一个简单的Haskell程序(并没有导入库,只有数据类型和纯函数)转换成一个非类型化的lambda演算术语的方法。一种很有希望的方法似乎是将程序编译成,然后将其转换为非类型化的lambda演算 如何使用GHC API加载Haskell程序并将其编译成Core?来自GHC文档中的: compileToCoreModule::GhcMonad m=>FilePath->m CoreModule 这是访问与 模块编译内核解析、类型检查并对模块进行去语法处理, 然后返回生成的核心模块(由
compileToCoreModule::GhcMonad m=>FilePath->m CoreModule
这是访问与
模块<代码>编译内核解析、类型检查并对模块进行去语法处理,
然后返回生成的核心模块(由模块名称组成,
类型声明和函数声明),如果成功
compileToCoreSimplified::GhcMonad m=>FilePath->m CoreModule
与compileToCoreModule类似,但调用简化器以返回
简化和整齐的核心
我通过查看GHC
模块列表,注意模块,注意deSugar
的结果,下载所有文档,并在文本中搜索ModGuts
,发现了这一点
最小示例
我们的示例将编译一个简单的模块,这样我们就可以看到内核的样子。它用于提供ghc libs目录的位置。内核将在内存中由一个包含。我们不能直接转储AST,因为没有CoreSyn
中描述的AST的Show
实例,但是CoreModule
的Outputable
实例将非常漂亮地打印核心,因此我们可以看到编译到核心
import GHC
import DynFlags
import Outputable (Outputable, showPpr)
import qualified GHC.Paths as Paths
import Data.Functor
runGhc'
负责编译核心模块所需的所有设置,无需import
s和TemplateHaskell
。我们使用完全关闭链接器,并告诉编译器使用什么也不生成
我们的整个示例程序将输出内核
这就产生了大量漂亮的打印核心
%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))
ghc有一个输出core-
ghc-ddump siml
的选项。另请看(ghc核心)[,它基本上只是通过一些后处理来包装ddump siml
。@user2407038这是真的,但据我所知,ghc core为我提供了一个人类可读的输出,我需要进一步解析。相反,我希望将核心表达式作为数据结构来进一步分析它。但它可能是一个很好的起点,谢谢。人类可读性ble输出也不是为了被解析而设计的,版本之间可能不太稳定。这个问题的核心版本有一个问题,并试图回答堆栈溢出问题。一个答案是旧版本的ghc。一个新问题问,然后从核心到二进制。非类型化的lambda演算只有函数,没有数据。而将数据编码为函数,ghc cote在这方面帮不了你。
compileExample :: Ghc CoreModule
compileExample = compileToCoreModule "prettyPrint2dList.hs"
showPpr' :: (Functor m, Outputable a, HasDynFlags m) => a -> m String
showPpr' a = (flip showPpr) a <$> getDynFlags
main = runGhc' (compileExample >>= showPpr') >>= putStrLn
data X = Y | Z
deriving (Eq, Show)
type R = [X]
type W = [R]
example = map (\x -> take x (cycle [Y, Z])) [0..]
main = undefined
%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))