parsing - 生成解析器,在另一个解析器的输出上运行接收到的解析器并单子(monad)连接结果

标签 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 (const $ unexpected typeName) 
               return . parse (subparser <* eof) ""

虽然我无法停止思考我没有像预期的那样使用 Monad 概念,但最终有一个更好的方法将内部解析器的结果与外部解析器合并,特别是关于它的失败。

有谁知道我该怎么做,或者这段代码是要做什么的?

PS - 我现在意识到我的类型简化可能不合适,也许我想要的是用 Either Monad 替换底层的 Identity Monad ....不幸的是,我对 monad 转换器还不够熟悉。

PS2 - 底层 monad 到底有什么用?

最佳答案

详细阐述 @Daniel Wagner 的答案...解析器通常使用 Parsec 构建的方式,您从解析特定字符(例如加号或数字)的低级解析器开始,然后在基础上构建解析器它们使用组合器(例如 many1 组合器,将读取单个数字的解析器转换为读取一个或多个数字的解析器,或者解析“一个或多个数字”后跟“的单子(monad)解析器”加号”后跟“一个或多个数字”)。

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

您通常不做的是编写一个解析器,该解析器吞噬输入流的一大块来生成一个 String 和另一个解析该 String 的解析器。 em>String (而不是原始输入流)并尝试将它们组合起来。这是一种不直接受秒差距支持的“垂直组合”,看起来不自然且非单子(monad)。

正如评论中所指出的,在某些情况下,垂直组合是最简洁的整体方法(例如当您将一种语言嵌入另一种语言的组件或表达式中时),但事实并非如此Parsec 解析器通常采用的方法。

您的应用程序的底线是仅生成 Stringcell 解析器过于专业而无用。对于 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'

现在,您可以编写一个解析正整数的自定义单元格解析器:

customCell :: Parser Int
customCell = read <$> many1 digit

并解析 CSV 文件:

> parse (csv customCell) "" "1,2,3\n4,5,6\n"
Right [[1,2,3],[4,5,6]]
>

在这里,“cell”是一个隐式上下文,其中提供的单元格显式地将逗号分隔的单元格解析为要馈送到不同解析器的字符串,而不是使用 cell 子解析器调用解析器在适当的点解析底层输入流,在该点,人们期望在输入流中间的一行中间有一个逗号分隔的单元格。

关于parsing - 生成解析器,在另一个解析器的输出上运行接收到的解析器并单子(monad)连接结果,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46186238/

相关文章:

android - 接收外语 Json(例如俄语)Android

regex - Powershell/正则表达式 : Get 8 Characters after given String

haskell - 输入中的语法错误(意外的 `=')

arrays - Haskell Data.Vector.Storable.unsafeFromForeignPtr 与 C 结构指针/数组字段

haskell - 在语义分析阶段获取行号信息(使用 Alex,Happy)

haskell - 在这种情况下,为什么在与嵌套的 StateT monadT 交互时不需要使用 'lift'?

haskell - monad 和 monad 函数的类约束

php - 在 MacOS Sierra 10.12.1 上安装/卸载 Apache2

python - 从网页获取国际字符?

scala - (如何)你能 curry 组成一元函数吗?