如何 map/bind FParsec 用户状态?

How to map/bind FParsec userstate?

我想通过解析器将一些状态线程化,但我不想为解析器的所有部分使用单一类型的状态,因为某些类型在解析器的某些部分没有意义,但在其他人中需要。我可以使用可选值或可区分的联合来创建更大更复杂的状态类型,但我认为这很丑陋。

所以我希望能够将函数映射到解析器的状态。

具体来说,我想要一个具有以下签名的函数

stateMap: (f:'a->'b) (p:Parser<'x,'a>) -> Parser<'x,'b>

FParsec 中是否存在这样的函数或运算符?如果不是,创建它的惯用方法是什么?

查了源码我的印象是现在没有这样的方法,实现起来也不是那么容易。 Parser<_> 被定义为喜欢 this:

type Parser<'Result, 'UserState> = CharStream<'UserState> -> Reply<'Result>

如果有办法将 CharStream<'a> 映射到 CharStream<'b> 那么我们就可以达到目标。

但是调查 CharStream<_>source 揭示了一些问题:

  1. CharStream<_>没有map
  2. CharStream<_>IDisposable,这意味着 FParsec 在解析开始时创建了 CharStream<_> 的一个实例,并且假设这会跟踪整个解析过程。在现有的基础上创建新的 CharStream<_> 并改用它似乎与设计不符。
  3. CharStream<_> 继承了 CharStream - 所以 CharStream 似乎在分页时必须做繁重的工作,而 CharStream<_> 只是为了将流与用户配对状态。如果 CharStream<_> 使用组合而不是继承,我们可以创建一个新的 CharStream<_>,它仍然使用已经存在的 CharStream,但继承是不可能的。我的猜测是这里选择继承是为了避免额外的取消引用,从而节省几个时钟周期(性能对解析器很重要)。

所以我认为复合用户状态的想法听起来很有趣,但据我所知,目前 FParsec 不支持它。