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]
其中 Pat
、Exp
、Type
和 Dec
与 Language.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
里的不太一样。打开 HsExpr
和 Exp
并排你会看到后者充满了像这样的类型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
不同,HsExpr
有 HsSplice
表示拼接。查看前两个构造函数的类型:
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
取决于)能够一次完成所有事情(例如,固定性是你必须提前给这个解析器的事情之一)。
我正在尝试学习一些模板 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]
其中 Pat
、Exp
、Type
和 Dec
与 Language.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 inLanguage.Haskell.TH.Syntax
)?
往里看HsSyn
,很明显AST和Language.Haskell.TH.Syntax
里的不太一样。打开 HsExpr
和 Exp
并排你会看到后者充满了像这样的类型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
不同,HsExpr
有 HsSplice
表示拼接。查看前两个构造函数的类型:
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
取决于)能够一次完成所有事情(例如,固定性是你必须提前给这个解析器的事情之一)。