haskell - 使用带有 Parsec 的累加器进行 Haskell 解析
问题描述
Haskell初学者在这里。
假设我有一个解析器,我提供了一些信息,它返回解析部分的结果和下一部分所需的信息。
readSection :: Info -> Parser (Section, Info)
我希望能够使用many
组合器解析多个部分,但我无法让这些类型工作。我需要某种方式让解析器接受Info
之前的计算。这种结构让我想起了折叠(因为之前的结果可以只存储在累加器中),但我不确定如何在这里应用它。
readSections :: Info -> Parser [Section]
readSections startInfo = do
let parser = readSection startInfo
-- ???
return $ many readSection
也许有更好的方法来做这样的事情,所以任何指导都将不胜感激。谢谢!
解决方案
如果您正在寻找现有的组合器,这看起来像是unfoldrM
from monad-loops
(以及其他地方)的应用程序。为了避免必须导入它,它可以定义为:
unfoldrM :: Monad m => (a -> m (Maybe (b, a))) -> a -> m [b]
unfoldrM f a = do
r <- f a
case r of
Nothing -> return []
Just (b, a') -> (b:) <$> unfoldrM f a'
基本上,它需要一个类型的初始种子a
并使用它来单子生成值和新种子。你的种子就是你的信息:你使用信息单子生成一个解析的部分加上一个新版本的信息。
您只需要坚持optionMaybe
提供Just
/Nothing
开关,以便unfoldrM
知道它何时到达所有部分的末尾:
readSections = unfoldrM (optionMaybe . readSection)
然而,作为一个 Haskell 初学者,看看你是如何从头开始做这类事情可能会有所帮助。组合器many
并不神奇。它基本上相当于相对简单的一元计算:
many p = (do x <- p
xs <- many p
return (x:xs))
<|> return []
因此,您可以readSections
以类似的方式从头开始编写一元计算:
readSections' :: Info -> Parser [Section]
readSections' i = (do -- try to read a section, getting updated info
(s, i') <- readSection i
-- read zero or more remaining sections with updated info
ss <- readSections' i'
-- return the sections
return (s:ss))
-- if no more sections to read, return an empty list
<|> return []
推荐阅读
- spring - GraphQL SPQR 中基于 WebSocket 的订阅
- google-coral - Coral 开发板:“读取 SSH 协议横幅时出错”
- reactjs - 类型 'boolean' 不可分配给类型 'false'.ts(2345)
- php - Prestashop 升级 1.7.8.0 PHP 7.4 后购物车不工作
- rust - 比较任何类型的 2 个变量的函数
- python - 具有 django 内容类型模型的复杂查询集
- javascript - 使用 d3.js 中切片数据中的特定列绘制折线图
- reactjs - 在反应应用程序上上传图像数组以存储在strapi中,但是在前端,当我运行控制台时它显示假路径,并且在strapi数据中它给出空对象
- python - 部署时如何使用 git 让我的项目显示在我的 repo 下?(django)
- java - 我需要正确理解 Java 中的抽象是什么?