GHC API: 查找范围内的所有函数(及其类型)

GHC API: Find all functions (and their types) in scope

我正在尝试列出(打印)给定模块范围内的所有函数(及其类型)。

例如,我有这个模块:

{-# LANGUAGE NoImplicitPrelude #-}

module Reverse where

import Prelude ((==), String)

myString :: String
myString = "string"

我正在尝试使用 GHC API (8.0.2),但我似乎无法找到存储我要查找的信息的位置。 我已经设法找到范围内的所有功能,(但不是他们的类型,)用这个代码:

import Data.IORef

import DynFlags
import GHC
import GHC.LanguageExtensions
import GHC.Paths (libdir)
import HscTypes
import NameEnv
import OccName
import Outputable
import RdrName
import TcRnTypes


main = runGhc (Just libdir) $ do
        liftIO $ print sets
        dflags <- getSessionDynFlags
        let compdflags =
                (foldl xopt_set dflags [Cpp, ImplicitPrelude, MagicHash])
        setSessionDynFlags compdflags
        target <- guessTarget "Reverse.hs" Nothing
        setTargets [target]
        load LoadAllTargets
        modSum <- getModSummary $ mkModuleName "Reverse"
        parsedModule <- parseModule modSum
        tmod <- typecheckModule parsedModule
        let (tcenv, moddets) = tm_internals_ tmod
        printO $ map (map gre_name) $ occEnvElts $ tcg_rdr_env tcenv

printO
    :: (GhcMonad m, Outputable a)
    => a -> m ()
printO a = do
    dfs <- getProgramDynFlags
    liftIO $ putStrLn $ showPpr dfs a

我得到这个输出:

[[String], [==], [myString]]

当然,这只是我需要的数据的一半。

GHC API 相当混乱,你必须习惯大量的缩写、类型同义词和风格各异的代码库,但是找到范围内所有内容的名称和类型应该是可能的。 否则,如果您打错字,GHC 无法告诉您您的函数不在范围内。

的确,一旦你对一个模块进行了类型检查,所有相关信息都是可用的。 首先,您需要函数的所有 Names,您可以使用以下代码获得:

parsedModule <- parseModule modSum
tmod <- typecheckModule parsedModule
let (tcenv, moddets) = tm_internals_ tmod
let names = concatMap (map gre_name) $ occEnvElts $ tcg_rdr_env tcenv

然后您需要查找 Names 以获得 TyThinglookupName。 你会得到一个 Maybe TyThingNothing 如果 Name 没有找到),当名称引用一个函数时,TyThing 将是 AnId i其中 i 是您要查找的内容。 Id 只是一个带有类型的名称。 然后,您可以使用 varType.

获取类型

您可能会争辩说,所有这些类型都使这个问题变得更加困难,但它们使我能够在不查看代码且没有文档的情况下弄清楚我需要做什么。