gpt4 book ai didi

haskell - 如何将 Haskell 编译成无类型 lambda 演算(或 GHC 核心)?

转载 作者:行者123 更新时间:2023-12-02 08:05:43 27 4
gpt4 key购买 nike

我正在寻找如何将简单的 Haskell 程序(没有导入的库,只有数据类型和纯函数)转换为非类型化 lambda 演算的术语。一个有前途的方法似乎是使用 GHC API将程序编译为 GHC core ,然后可以将其转换为无类型 lambda 演算。

如何使用GHC API加载Haskell程序并将其编译到Core中?

最佳答案

来自 GHC module documentation在 ghc 文档中:

compileToCoreModule :: GhcMonad m => FilePath -> m CoreModule

This is the way to get access to the Core bindings corresponding to a module. 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.

compileToCoreSimplified :: GhcMonad m => FilePath -> m CoreModule

Like compileToCoreModule, but invokes the simplifier, so as to return simplified and tidied Core.

我通过查看 GHC 列表找到了这个模块,注意 Desugar 模块,注意到 ModGuts 结果为 deSugar ,下载所有文档,然后搜索文本 ModGuts .

最小示例

我们的示例将编译一个简单的模块,以便我们可以看到核心的样子。它使用 ghc-paths提供 ghc libs 目录的位置。核心在内存中将由 CoreModule 表示包含 CoreBind s 的列表。我们无法直接转储 AST,因为没有 Show CoreSyn 中描述的 AST 实例,但是Outputable CoreModule 的实例将漂亮地打印核心,以便我们可以看到我们已编译到核心。

import GHC
import DynFlags
import Outputable (Outputable, showPpr)
import qualified GHC.Paths as Paths

import Data.Functor

runGhc'负责编译核心模块所需的所有设置 import s 和 no TemplateHaskell 。我们完全关闭链接器 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

将模块编译到核心包括使用 guessTarget 设置目标。和 addTarget ,可选择使用 load 加载依赖项,使用 depanel 构建模块图, find正确的 ModSummary 在模块图中,使用 parseModule 解析模块,输入 typecheckModule 进行检查,用 desugarModule 脱糖,将其转换为 ModGuts coreModule 来自DesugaredMod脱糖结果的实例,并从 ModGuts 中提取核心。所有这些都被 compileToCoreModule 包装在一个漂亮的包中。 .

compileExample :: Ghc CoreModule
compileExample = compileToCoreModule "prettyPrint2dList.hs"

我们的整个示例程序将输出核心 showPpr .

showPpr' :: (Functor m, Outputable a, HasDynFlags m) => a -> m String
showPpr' a = (flip showPpr) a <$> getDynFlags

main = runGhc' (compileExample >>= showPpr') >>= putStrLn

编译上面的例子需要-package ghc标记以公开通常隐藏的 ghc api 包。

我们将编译到核心的示例模块,"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

这会产生大量打印精美的核心。

%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))

关于haskell - 如何将 Haskell 编译成无类型 lambda 演算(或 GHC 核心)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27635111/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com