Template Haskell: 有解析String和returns Q Exp的函数(或特殊语法)吗?

Template Haskell: Is there a function (or special syntax) that parses a String and returns Q Exp?

我正在尝试学习一些模板 Haskell 和准引用,我正在寻找一个接受 String 并将其解析为 Q Exp 的函数,因此类型是:

String -> Q Exp

尝试搜索 hoogle,但我看到的结果与将字符串文字提升到 Q Exp 有关,我找到的最接近的是 Language.Haskell.TH.dyn,它完全符合我的要求,但仅针对单个变量。

还有其他选择吗?例如。一个特殊的语法?我正处于熟悉 [||]$() 的过程中,所以也许也有用于此目的的东西?

一个我想象它如何工作的例子:

runQ (parse "(1+)") == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing

另外,我知道这一点

runQ [| (1+) |] == InfixE (Just (LitE (IntegerL 1))) (VarE GHC.Num.+) Nothing

但这不适用于可变字符串,因为——可以理解——内部的字符串被视为文字。

runQ [| "(1+)" |] == LitE (StringL "(1+)")

编辑 (2015-07-25): 我已经开始使用 haskell-src-meta,到目前为止它似乎运行良好。但是 cabal install 确实需要相当多的时间(在我的机器上大约需要 10 分钟)。真可惜,我的包其实很小,我希望能快点安装。任何人都知道具有较小依赖性的解决方案吗?

大家已经说了haskell-src-meta提供

parsePat :: String -> Either String Pat
parseExp :: String -> Either String Exp
parseType :: String -> Either String Type
parseDecs :: String -> Either String [Dec]

其中 PatExpTypeDecLanguage.Haskell.TH.Syntax.

相同

Why doesn't GHC expose its own parser?

确实如此。使用 ghci -package ghc 启动 GHCi(ghc 默认情况下是一个隐藏包)并且您可以导入 Parser. It has functions to parse String into preliminary ASTs (whose data declarations are in HsSyn)用于模式、表达式、类型和声明。

OK, then why does there not exist a library that uses this parser and converts its output to be the AST from template-haskell (the one in Language.Haskell.TH.Syntax)?

往里看HsSyn,很明显AST和Language.Haskell.TH.Syntax里的不太一样。打开 HsExprExp 并排你会看到后者充满了像这样的类型PostTc id <some-other-type>PostRn id <some-other-type>。随着 AST 从解析器传递到重命名器再到类型检查器,这些点点滴滴都被慢慢填充。例如,在我们进行类型检查之前,我们甚至不知道运算符的固定性!

为了实现我们想要的功能,我们需要 运行 不仅仅是解析器(至少还有重命名器和类型检查器,也许更多)。想象一下:每次你想要解析像 "1 + 2" 这样的小表达式时,你仍然需要输入检查一堆导入。即使那样,转换回 Language.Haskell.TH.Syntax 也不是在公园里散步:GHC 有很多特点,比如它自己特殊的全球存储名称和标识符的方式。

Hmmm... but what does GHC do with quasi-quotes?

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

HsTypedSplice :: id -> LHsExpr id -> HsSplice id.   -- things like [|| 1 + 2 ||]
HsUntypedSplice :: id -> LHsExpr id -> HsSplice id  -- things like [| 1 + 2 |]

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

So is it fundamentally impossible to use GHC's parser

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