haskell-生成
介绍
如果您想生成haskell源代码,可以构建haskell-src-exts AST,然后将其打印出来。但这很容易出错,因为haskell-src-extss不包含标记,它是带有类型的AST。该库旨在填补空白,为haskell-src-exts表达式添加类型信息,并为您管理导入。
入门
首先,您需要导入此库:
导入语言。哈斯克尔。生成
此模块重新导出语言。哈斯克尔。分机。语法
因为haskell-generate是在此基础上构建的。
haskell-generate有两种主要类型。第一个是单子生成
和类型别名ExpG公司
. The生成
monad用于跟踪所需的导入。它还允许生成唯一的名称。出口G t
只是中的一个操作生成
返回类型表达式的monadt吨
.
如何构建表达式?中的函数有许多预定义表达式前奏曲。这允许您仅使用这些表达式并将其组合为新表达式。例如,让我们定义一个表达式来读取名为“names”的文件:
readNamesFile'::ExpG(IO字符串)readNamesFile“=readFile”<>$expr“names”
这里我们使用(<>$)
应用读取文件'
表达式转换为字符串姓名
.读取文件'
是haskell generate已经提供的表达式之一。haskell-generate提供的所有表达式都以撇号结尾。你可以在模块中找到更多语言。哈斯克尔。生成。前奏曲参考
. The快递
函数用于提升管柱姓名
转换为类型的表达式ExpG字符串
.
现在我们有了一个表达式,我们需要将其绑定到模块中的一个名称。对于这个工作,我们使用另一个单子模块M
莫纳德。它允许您将表达式绑定到名称,然后生成具有这些名称的模块。
以下是我们如何生成模块:
myModule::模块GmyModule=dod<-addDecl(Ident“main”)$applyE2绑定“readNamesFile”“putStrLn”return$Just[exportFun d]
模块G
还是中某个操作的类型同义词模块M
莫纳德。它必须返回Nothing(省略导出列表)或导出列表。在这种情况下,我们导出“main”函数,我们之前使用添加拒绝
.
剩下要做的唯一一件事就是为模块生成实际的源代码,为此我们使用发电机模块
函数,它将模块名称作为参数:
主::IO()main=putStrLn$generateModule myModule“main”
如果运行该程序,将获得以下输出:
模块Main(Main),其中进口合格GHC。底座导入合格的系统。IO(输入输出)主要的=(GHC.Base.>>=)(System.IO.readFile['n','a','m','e','s'])系统。IO输出StrLn
如果运行此代码,您将获得“名称”文件的内容。代码有点难看,并且使用符合条件的导入以避免名称冲突,但它有效。
导入函数
到目前为止,我们只使用了来自语言。哈斯克尔。生成。前奏曲参考
,但通常您会希望使用其他模块中可能需要使用的定义。
您可以使用useValue(使用值)
来自haskell-generate。让我们看看useValue(使用值)
:
useValue::字符串->名称->ExpG t
useValue(使用值)
采用定义函数的模块名和函数名。它返回任何类型的表达式。此函数是不安全的,因为它无法检查返回的类型是否实际上是函数的类型。这就是为什么你通常useValue(使用值)
显式类型签名。
例如,假设我们想使用函数排列
来自数据。列表。我们为其编写了以下定义:
permutations’::ExpG([a]->[[a]])——这里我们给出了permutations的显式类型。这是不检查的,所以请确保它实际上是正确的!permutations'=useValue“Data.List”(Ident“permutations”)--“permulations”是标识符,而不是符号,所以我们使用“Ident”构造函数。
使用TH自动导入函数
如果要导入的函数在编译时已经可用,可以使用模板haskell代码语言。哈斯克尔。生成。真实航向
以生成表达式定义。作为一个例子,这就是我们在前奏曲中使用的方法。
使用上一节中的示例,我们还可以导入排列
功能如下:
--在文件顶部:{-#LANGUAGE TemplateHaskell#-}—启用模板haskell导入数据。列表(排列)——函数需要在编译时可用declareFunction的排列——这会生成与上面相同的代码,但更安全,因为您不必自己指定类型。
贡献
如果您有想法、问题或错误报告,请在github上打开一个问题。你也可以在#haskell频道的freenode上找到我,我的昵称是bennofs。