我需要帮助设计带有 monad 的非严格语法解析器。语法结构如下:
- 标题
- 第 1 节
- 第2节
- ...
这些部分中的每一个都可能丢失,并且流可能在任何地方结束,因此,我需要返回到目前为止我已经解析的内容。
我成功地使用 State monad 将我的解析器构造成每个部分的 s => (a, s)类型的函数。状态s保存其余的输入和此刻抓取的数据。在类似 Scala 的伪代码中:
val parser = for {
_ <- readHeader
_ <- readSection1
_ <- readSection2
- <- ...
} yield ()
parser(input)
现在,我还想实现提前终止,这样解析器就不会尝试读取 EOF 上的进一步输入。例如,如果在阅读标题后到达 EOF,我想返回并且不进一步阅读。
这是我到目前为止得到的:
import scalaz._
import Scalaz._
object Playground extends App {
type Stream = String
type Mined = List[String]
type ParserState = (Stream, Mined)
type MyEither[+T] = Either[ParserState, T]
val s1 = StateT[MyEither, ParserState, Unit] { s =>
Right((("input at s1", add(s, "header")), ()))
}
val s2 = StateT[MyEither, ParserState, Unit] { s =>
Right((("input at s2", add(s, "section1")), ()))
}
val s3 = StateT[MyEither, ParserState, Unit] { s =>
Left(s)
}
val s4 = StateT[MyEither, ParserState, Unit] { s =>
Right((("input at s4", add(s, "section3")), ()))
}
def add(s: ParserState, mined: String): Mined = mined :: s._2
val parser =
for {
_ <- s1
_ <- s2
_ <- s3
_ <- s4
} yield ()
println(parser.run(("input", List())))
}
印刷:
Left((input at s2,List(section1, header)))
这种方法实用吗?我想知道有没有更好的解决方案?