模板Haskell:是否有解析String并返回Q Exp的函数(或特殊语法)?

Wiz*_*zek 20 haskell template-haskell

我正在尝试学习一些模板Haskell和Quasi Quotation,我正在寻找一个函数,它接受String并解析它Q Exp,所以类型是:

String -> Q Exp
Run Code Online (Sandbox Code Playgroud)

尝试搜索hoogle,但我看到的结果与提升字符串文字有关Q Exp,而我找到的最接近的Language.Haskell.TH.dyn是我想要的,但仅适用于单个变量.

还有其他选择吗?例如一个特殊的语法?我只是在自己熟悉的过程中[||]$(),所以也许也有一些是为了这个目的呢?

我想象它会起作用的一个例子:

runQ (parse "(1+)") == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing
Run Code Online (Sandbox Code Playgroud)

另外,我知道这一点

runQ [| (1+) |] == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing
Run Code Online (Sandbox Code Playgroud)

但这不适用于变量字符串,因为 - 可以理解 - 里面的字符串被视为文字.

runQ [| "(1+)" |] == LitE (StringL "(1+)")
Run Code Online (Sandbox Code Playgroud)

编辑(2015-07-25):我已经开始使用了haskell-src-meta,到目前为止似乎运行良好.但是它需要相当长的时间cabal install(我的机器上大约10分钟).这是一个耻辱,我的包实际上相当小,我想如果安装可以很快.任何人都知道具有较小依赖性的解决方案?

Ale*_*lec 5

正如大家已经说过的haskell-src-meta那样

parsePat :: String -> Either String Pat
parseExp :: String -> Either String Exp
parseType :: String -> Either String Type
parseDecs :: String -> Either String [Dec]
Run Code Online (Sandbox Code Playgroud)

其中PatExpTypeDec与 from 相同Language.Haskell.TH.Syntax


为什么 GHC 不公开自己的解析器?

确实如此。ghci -package ghc使用(默认情况下是隐藏包)启动 GHCi ghc,然后您可以导入Parser. 它具有解析模式、表达式、类型和声明的String初步 AST(其数据声明在 中)的函数。HsSyn

好的,那么为什么不存在一个库使用这个解析器并将其输出转换为来自template-haskell( 中的那个Language.Haskell.TH.Syntax)的 AST 呢?

看看里面HsSyn,很明显 AST 与 中的不太一样Language.Haskell.TH.Syntax。并排打开HsExprandExp和 ,您会发现后者充满了像PostTc id <some-other-type>和 之类的类型PostRn id <some-other-type>。当 AST 从解析器传递到重命名器再到类型检查器时,这些零碎的东西都会慢慢地被填充。例如,我们甚至不知道运算符的固定性,直到我们进行类型检查!

为了实现我们想要的功能,我们需要运行的不仅仅是解析器(至少还有重命名器和类型检查器,也许更多)。想象一下:每次你想解析一个小表达式时,"1 + 2"你仍然需要输入检查一堆导入。即便如此,转换回Language.Haskell.TH.SyntaxGHC 也不是一件容易的事:GHC 有多种特性,比如它自己特殊的全局存储名称和标识符的方式。

嗯……但是 GHC 对准引号有什么作用呢?

这就是最酷的部分!与 不同的是,Exp代表拼接。查看前两个构造函数的类型:HsExprHsSplice

HsTypedSplice :: id -> LHsExpr id -> HsSplice id.   -- things like [|| 1 + 2 ||]
HsUntypedSplice :: id -> LHsExpr id -> HsSplice id  -- things like [| 1 + 2 |]
Run Code Online (Sandbox Code Playgroud)

请注意,他们没有存储String,而是已经存储了 AST!拼接与 AST 的其余部分同时解析。就像 AST 的其余部分一样,拼接将被传递到重命名器、类型检查器等,其中缺失的信息将被填充。

那么是不是根本就无法使用GHC的解析器呢?

可能不会。但将其从 GHC 的其余部分中解脱出来可能相当困难。haskell-src-exts如果要使用 GHC 的解析器,我们还必须运行类型检查器和重命名器,仅使用一个独立的解析器(这取决于什么)可能会更优雅和简单,Haskell-src-meta它能够一次完成所有事情(固定性)例如,是您必须提前提供给此解析器的内容之一)。