Parsing 底层Parsec单子
我使用的许多Parsec组合符的类型如下:Parsing 底层Parsec单子,parsing,haskell,monads,monad-transformers,Parsing,Haskell,Monads,Monad Transformers,我使用的许多Parsec组合符的类型如下: foo :: CharParser st Foo CharParser定义为: 因此,CharParser是涉及GenParser的类型同义词,其本身定义为: GenParser是另一种类型的同义词,使用Parsec赋值,定义如下: 因此,Parsec是ParsecT的一个部分应用程序,其本身以类型列出: data ParsecT s u m a 除此之外: “ParsecT s u m a是流类型为s、用户状态类型为u的解析器, 基础monad
foo :: CharParser st Foo
CharParser
定义为:
因此,CharParser
是涉及GenParser
的类型同义词,其本身定义为:
GenParser
是另一种类型的同义词,使用Parsec
赋值,定义如下:
因此,Parsec
是ParsecT
的一个部分应用程序,其本身以类型列出:
data ParsecT s u m a
除此之外:
“ParsecT s u m a是流类型为s、用户状态类型为u的解析器,
基础monad m和返回类型a。“
什么是潜在的单子?特别是,当我使用
CharParser
解析器时,它是什么?我看不到它在堆栈中的插入位置。使用中的列表单子从一个不明确的解析器返回多个成功的解析与此有关系吗?GenParser是根据Parsec定义的,而不是ParsecT。Parsec反过来定义为
type Parsec s u = ParsecT s u Identity
因此,答案是当使用CharParser时,底层monad是Identity monad。在您的例子中,底层monad是
Identity
。然而,ParsecT与大多数monad转换器不同,它是monad
类的实例,即使类型参数m
不是。如果查看源代码,您将注意到实例声明中缺少“(Monad m)=>
”
然后你会问自己,“如果我有一个非平凡的monad堆栈,它会被用在哪里?”
这个问题有三个答案:
uncon
流外的下一个令牌:
class (Monad m) => Stream s m t | s -> t where
uncons :: s -> m (Maybe (t,s))
请注意,uncon
接受一个s
(令牌流t
)并返回封装在monad中的结果。这允许一个人在获取下一个令牌的过程中做一些有趣的事情lift(x::ma)::ParsecT s u m a
m
被Identity
替换的位置)返回包装在这个monad中的结果m
,你在想,结果列表一定隐藏在那里的某个地方。事实并非如此
出于效率考虑,Parsec选择了Hutton和Meijer的结果列表中的第一个匹配结果。让我们扔掉Hutton和Meijer列表尾部未使用的结果,以及令牌流的前端,因为我们从不回溯。在parsec中,给定组合解析器ab
,如果a
使用任何输入b
,则永远不会对其求值。解决方法是try
,如果a
失败,它会将状态重置回原来的状态,然后评估b
您在评论中询问这是否是使用
或者或者来完成的。答案是“几乎但不完全”。如果你看一下低级别的run*
函数,你会发现它们返回一个代数类型,告诉天气输入被消耗,然后是一秒钟,给出结果或错误消息。这些类型的工作方式类似于,
,但即使是它们也不能直接使用。我将向您介绍Antoine Later的文章,它将解释这是如何工作的,以及为什么这样做。谢谢,我编辑了我的问题以包括这一步。所以它是monad变压器的基础。我相信这与Hutton/Meijer论文中描述的模棱两可的解析没有关系。那么,list monad的使用是否出现在Parsec解析器中的任何地方?Parsec是唯一不含糊的吗?如果是这样的话,那是用编码的吗?也许是或者或者或者是?底层的单子不是被parsec本身使用的,因此它不会影响歧义性。我想我想问的是Hutton/Meijer论文中列表单子之间的关系;以及在Parsec中使用的和类型。
data ParsecT s u m a
type Parsec s u = ParsecT s u Identity
class (Monad m) => Stream s m t | s -> t where
uncons :: s -> m (Maybe (t,s))