F# 如何映射/绑定FParsec用户状态?

F# 如何映射/绑定FParsec用户状态?,f#,fparsec,F#,Fparsec,我希望通过解析器来执行某些状态,但我不希望解析器的所有部分都有一个单独的状态类型,因为有些类型在解析器的某些部分没有意义,但在其他部分中是需要的。我可以创建一个更大、更复杂的状态类型,可以使用可选值,也可以使用一个有区别的联合,但我认为这很难看 所以我希望能够将函数映射到解析器的状态 具体地说,我想要一个具有以下签名的函数 stateMap: (f:'a->'b) (p:Parser<'x,'a>) -> Parser<'x,'b> stateMap:(f:

我希望通过解析器来执行某些状态,但我不希望解析器的所有部分都有一个单独的状态类型,因为有些类型在解析器的某些部分没有意义,但在其他部分中是需要的。我可以创建一个更大、更复杂的状态类型,可以使用可选值,也可以使用一个有区别的联合,但我认为这很难看

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

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

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

FParsec中是否存在此类函数或运算符?如果没有,创建它的惯用方法是什么?

从检查源代码来看,我的印象是,现在没有这样的方法,实现起来也不那么容易<代码>解析器定义如下:

type Parser=CharStream
如果有一种方法可以映射CharStream,那么我们就可以达到目标

但是,调查for
CharStream
会发现一些问题:

  • 对于
    CharStream
    ,没有
    map
  • CharStream
    IDisposable
    ,这意味着
    FParsec
    在解析开始时创建
    CharStream
    的一个实例,并假设它跟踪整个解析过程。在现有的基础上创建一个新的
    CharStream
    ,并使用与设计不匹配的内容
  • CharStream
    继承了
    CharStream
    ——因此
    CharStream
    似乎在分页时起了很大的作用,而
    CharStream
    只是将流与用户状态配对。如果
    CharStream
    使用组合而不是继承,我们可以创建一个新的
    CharStream
    ,它仍然使用已经存在的
    CharStream
    ,但是继承是不可能的。我的猜测是,这里选择继承是为了避免额外的deref,从而节省一些时钟周期(性能对于解析器很重要)

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

    许多FParsec功能都基于更改/未更改的用户状态。我没有证据,但我真诚的猜测是,您可能需要考虑一个复杂的用户状态,它被实现为输入和输出两种类型的判别式联合(或另一种组合)。
    type Parser<'Result, 'UserState> = CharStream<'UserState> -> Reply<'Result>