- 问题. 是否有一种方法可以定义一个操作符,使得由该操作符分隔的一系列值产生一个扁平的元组?
我一直在寻找一个简洁的表达我的问题的方式,所以请继续阅读详细信息和示例...
描述
我正在为Parsec编写一些辅助操作符,首先是以下内容:
(<@) :: GenParser tok st a -> (a -> b) -> GenParser tok st b
p <@ f = do {
x <- p ;
return (f x)
}
(<>) :: GenParser tok st a -> GenParser tok st b -> GenParser tok st (a, b)
p <> q = do {
x <- p ;
y <- q ;
return (x, y)
}
以下是它们的工作原理:
parseTest ((many upper) <@ length) "HELLO"
5
parseTest (many upper) <> (many lower) "ABCdef"
("ABC", "def")
不幸的是,由<>
分隔的一系列解析器将导致嵌套元组,例如:
parseTest (subject <> verb <> object) "edmund learns haskell"
(("edmund", "learns"), "haskell")
相比于相对更优秀的:
("edmund", "learns", "haskell")
我正在寻找一种定义
<>
的方式,以便:p1 :: GenParser tok st a ; p2 :: GenParser tok st b ; p3 :: GenParser tok st c
p1 <> p2 :: GenParser tok st (a, b)
p1 <> p2 <> p3:: GenParser tok st (a, b, c)
...
我认为我从未见过一个Haskell程序像这样构建长度为n
的元组类型(在编译时已知)。而且我怀疑定义同时具有两种类型的运算符可能会很困难:
GenParser tok st a -> GenParser tok st b) -> GenParser tok st (a, b)
GenParser tok st (a, b) -> GenParser tok st c) -> GenParser tok st (a, b, c)
-- 如何在编译时区分由<>产生的元组和简单的返回类型?我只能猜测需要额外的语法。因此,我不确定这是一个好主意还是可能的。即使对我的情况来说这不是一个好主意,我也很想知道如何做到这一点(如果不可能,我也很想知道如何做到这一点)。
-- 跟进问题(如果这个疯狂的方案是可能的)。如何注释 <> 链中的一个项目以使其不包含在结果元组中?
例如,假设后缀注释为 #:
p1 :: GenParser tok st a
p2 :: GenParser tok st b
p1 <> keyword "is" <# <> p2 :: GenParser tok st (a, b)
背景
大约在2006年,我在大学时学习了解析器组合。当时我们使用的一个库中,<@
和 <>
操作符类似于我的尝试。我不知道这个库是什么;可能是由研究生为教我们课程而编写的。无论如何,它似乎既不是Parsec,也不属于 `Text.Parser.Combinators` 中的基础解析器组合。
- 奖励问题。 `Text.ParserCombinators.ReadP`/`ReadPrec` 中的基础解析器组合与 Parsec 有什么区别?
我记得这个库也是不确定性的,每次调用解析器时都会返回一组可能的解析结果和剩余未解析的输入。 (成功、完整、明确的解析将导致 [(parseresult, "")]
。)
- 最后一个问题。 如果你听说过这个,能告诉我它是什么吗?(为怀旧之情)