简体   繁体   English

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

[英]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

Minimal Example 最小的例子

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实例,但是CoreModuleOutputable实例将完全打印核心,因此我们可以看到我们编译为核心。

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 . 编译模块到核心包括设置目标用的guessTargetaddTarget ,任选加载与依赖load ,与构建模块图表depanelfind荷兰国际集团的正确ModSummary在模块图形,解析与所述模块parseModule ,类型与检查它typecheckModule ,使用desugarModule对其进行desugarModule ,使用来自DesugaredMod实例的DesugaredMod将其转换为ModGutscoreModule 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM