Parsing 生成一个解析器,该解析器在另一个解析器的输出上运行接收到的解析器,并以一元方式联接结果

Parsing 生成一个解析器,该解析器在另一个解析器的输出上运行接收到的解析器,并以一元方式联接结果,parsing,haskell,monads,monad-transformers,parsec,Parsing,Haskell,Monads,Monad Transformers,Parsec,给定以下类型和函数,用于将CSV字段的字段解析为字符串: type Parser resultType = ParsecT String () Identity resultType cell :: Parser String 我已经实现了以下功能: customCell :: String -> Parser res -> Parser res customCell typeName subparser = cell >>= either (cons

给定以下类型和函数,用于将CSV字段的字段解析为字符串:

type Parser resultType = ParsecT String () Identity resultType
cell :: Parser String 
我已经实现了以下功能:

customCell :: String -> Parser res  -> Parser res
customCell typeName subparser = 
  cell
    >>= either (const $ unexpected typeName) 
               return . parse (subparser <* eof) ""
customCell::String->Parser res->Parser res
customCell typeName子Parser=
细胞
>>=其中一个(常量$unexpected typeName)

返回。作语法分析(subparser遗憾的是,据我所知,Haskell没有一个解析器库或解析器生成器支持这样的垂直解析器组合。类似于您所写的内容,它已经非常好了。Dang!

详细阐述@Daniel Wagner的答案……按照通常使用Parsec构建解析器的方式,您从解析特定c的低级解析器开始字符(例如,加号或数字),然后使用组合器(如
many1
combinator,将读取单个数字的解析器转换为读取一个或多个数字的解析器,或将“一个或多个数字”后跟“加号”再后跟“一个或多个数字”的一元解析器)在其上构建解析器

然而,每个解析器,无论是低级数字解析器还是高级“加法表达式”解析器,都旨在直接应用于相同的输入流

您通常不做的是编写一个解析器,将输入流中的一块内容分解成一个
字符串
,然后编写另一个解析器,对该
字符串
(而不是原始输入流)进行解析,并尝试将它们组合起来。这是一种“垂直组合”Parsec并不直接支持这一点,它看起来不自然,也不是一元的

正如在评论中指出的,在某些情况下,垂直组合是最干净的总体方法(例如,当一种语言嵌入到另一种语言的组件或表达式中时),但它不是Parsec解析器通常采用的方法

应用程序中的底线是,只生成
字符串的
单元格
解析器过于专业化,不太有用。CSV文件更有用的Parsec框架是:

import Text.Parsec
import Text.Parsec.String

-- | `csv cell` parses a CSV file each of whose elements is parsed by `cell`
csv :: Parser a -> Parser [[a]]
csv cell = many (row cell)

-- | `row cell` parses a newline-terminated row of comma separated
--   `cell`-expressions
row :: Parser a -> Parser [a]
row cell = sepBy cell (char ',') <* char '\n'

在这里,不是使用一个
单元格
子parser来显式地将逗号分隔的单元格解析为字符串,以提供给另一个解析器,“cell”是一个隐含的上下文,在这个上下文中调用一个提供的单元解析器来解析底层的输入流,在适当的点上,在输入流中间的一行中会有一个逗号分隔的单元格。

我不确定垂直分析器的组成是什么意思。你介意扩大一点吗?关于你所要求的:一种采用
解析器Foo[Bar]的方法
解析器Bar Baz
并将其转换为
解析器Foo Baz
。哦,我明白了。像这样简单的类型,目标比OP的问题要明确得多。谢谢你的澄清!我编写了一个支持垂直组合的解析器库
https://github.com/quickdudley/phaser
customCell :: Parser Int
customCell = read <$> many1 digit
> parse (csv customCell) "" "1,2,3\n4,5,6\n"
Right [[1,2,3],[4,5,6]]
>