内省 GHC 模块中的函数名称
Introspecting function names in a GHC module
在 Glasgow Haskell 编译器中有没有一种方法可以内省模块中所有函数的名称?
我正在尝试创建一个自动数据库迁移系统,给定迁移模块的名称,内省内部函数的名称并一次调用它们。
类似
doMigrations("Migrations.M_2015")
doMigrations("Migrations.M_2016")
-- ...
其中 Migration.M_2015
包含
module Migration.M_2015
where
migration_2015_01_02 :: DbConnection -> Status
migration_2015_01_02 connection =
-- ...
每个 doMigration
将反映其模块中的迁移函数的名称,并且仅调用那些之前未被 运行 的函数(名称保存在 DB table 中)。这只会在应用程序启动时调用,因此性能不是大问题。反射可以在编译时或 运行 时发生。
为此,您需要使用 GHC API——它包含在 ghc 包中(隐藏的)——但文档很少。
我在这里附上了一个简单的程序,它将打印出模块中导出的顶级项目的列表。这应该作为一个起点。这是一个带有两个参数的小型命令行实用程序——一个模块名称和单词 "class"、"data"、"function"。所以,例如:
test Prelude function
将打印模块导出的函数列表(那些不是构造函数或在 class 中定义的函数)。
为了编译它(假设它在 test.hs
中)你需要做:
ghc -package ghc test
为了使 GHC API 包可用。
代码如下:
import Data.List ( (\) )
import Data.Maybe (fromJust, catMaybes)
import System.Environment (getArgs)
-- the GHC API stuff
import GHC
import GHC.Paths (libdir)
import ConLike ( ConLike(..) )
import Outputable (showPpr, showSDocUnqual)
import Var (tyVarName)
showU dfs = showSDocUnqual dfs . pprParenSymName
main = do
(mn : ty : _) <- getArgs
a <- runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
mm <- lookupModule (mkModuleName mn) Nothing
mi <- fmap fromJust $ getModuleInfo mm
res <- fmap catMaybes $ mapM lookupName (modInfoExports mi)
return $ case ty of
"class" -> [showU dflags c' | c@(ATyCon c') <- res, isClassTyCon c']
"data" -> [showU dflags c' | c@(ATyCon c') <- res, (not . isClassTyCon) c']
"function" -> let cf = map getName $ concat [(classMethods . fromJust . tyConClass_maybe) c' | c@(ATyCon c') <- res, isClassTyCon c']
df = map getName $ concat [ tyConDataCons c' | c@(ATyCon c') <- res, (not . isClassTyCon) c']
ff = [ getName c | c@(AnId{}) <- res] \ cf
fd = [ getName c | c@(AConLike (RealDataCon{})) <- res] \ df
in [showU dflags x | x <- ff ++ fd]
_ -> ["need to specify: class, data, or function"]
print a
classes 列表和定义的数据非常简单。已定义函数的列表包括在 classes 和构造函数中定义的函数。上面的代码,对于函数,排除了这些(使用 \ cf
和 \ df
)。
a
是生成的函数(或 class 或数据)名称列表。
调用这些函数的代码将成为不同问题(和答案)的主题。
lookupModule
是加载模块进行分析的函数。
getModuleInfo
和 modInfoExports
的组合得到 "stuff" 的列表,其中包括从模块导出的函数列表。
其余代码是关于以可用形式获取这些名称。
在 Glasgow Haskell 编译器中有没有一种方法可以内省模块中所有函数的名称?
我正在尝试创建一个自动数据库迁移系统,给定迁移模块的名称,内省内部函数的名称并一次调用它们。
类似
doMigrations("Migrations.M_2015")
doMigrations("Migrations.M_2016")
-- ...
其中 Migration.M_2015
包含
module Migration.M_2015
where
migration_2015_01_02 :: DbConnection -> Status
migration_2015_01_02 connection =
-- ...
每个 doMigration
将反映其模块中的迁移函数的名称,并且仅调用那些之前未被 运行 的函数(名称保存在 DB table 中)。这只会在应用程序启动时调用,因此性能不是大问题。反射可以在编译时或 运行 时发生。
为此,您需要使用 GHC API——它包含在 ghc 包中(隐藏的)——但文档很少。
我在这里附上了一个简单的程序,它将打印出模块中导出的顶级项目的列表。这应该作为一个起点。这是一个带有两个参数的小型命令行实用程序——一个模块名称和单词 "class"、"data"、"function"。所以,例如:
test Prelude function
将打印模块导出的函数列表(那些不是构造函数或在 class 中定义的函数)。
为了编译它(假设它在 test.hs
中)你需要做:
ghc -package ghc test
为了使 GHC API 包可用。
代码如下:
import Data.List ( (\) )
import Data.Maybe (fromJust, catMaybes)
import System.Environment (getArgs)
-- the GHC API stuff
import GHC
import GHC.Paths (libdir)
import ConLike ( ConLike(..) )
import Outputable (showPpr, showSDocUnqual)
import Var (tyVarName)
showU dfs = showSDocUnqual dfs . pprParenSymName
main = do
(mn : ty : _) <- getArgs
a <- runGhc (Just libdir) $ do
dflags <- getSessionDynFlags
setSessionDynFlags dflags
mm <- lookupModule (mkModuleName mn) Nothing
mi <- fmap fromJust $ getModuleInfo mm
res <- fmap catMaybes $ mapM lookupName (modInfoExports mi)
return $ case ty of
"class" -> [showU dflags c' | c@(ATyCon c') <- res, isClassTyCon c']
"data" -> [showU dflags c' | c@(ATyCon c') <- res, (not . isClassTyCon) c']
"function" -> let cf = map getName $ concat [(classMethods . fromJust . tyConClass_maybe) c' | c@(ATyCon c') <- res, isClassTyCon c']
df = map getName $ concat [ tyConDataCons c' | c@(ATyCon c') <- res, (not . isClassTyCon) c']
ff = [ getName c | c@(AnId{}) <- res] \ cf
fd = [ getName c | c@(AConLike (RealDataCon{})) <- res] \ df
in [showU dflags x | x <- ff ++ fd]
_ -> ["need to specify: class, data, or function"]
print a
classes 列表和定义的数据非常简单。已定义函数的列表包括在 classes 和构造函数中定义的函数。上面的代码,对于函数,排除了这些(使用 \ cf
和 \ df
)。
a
是生成的函数(或 class 或数据)名称列表。
调用这些函数的代码将成为不同问题(和答案)的主题。
lookupModule
是加载模块进行分析的函数。
getModuleInfo
和 modInfoExports
的组合得到 "stuff" 的列表,其中包括从模块导出的函数列表。
其余代码是关于以可用形式获取这些名称。