F# 这是解析器组合器库的合理基础吗?
我最近一直在与FParsec合作,我发现缺少泛型解析器是我的一个主要停止点。我对这个小库的目标是简单性以及对通用输入的支持。你能想出任何可以改善这一点的补充,或者有什么特别糟糕的吗 open LazyList type State<'a, 'b> (input:LazyList<'a>, data:'b) = member this.Input = input member this.Data = data type Result<'a, 'b, 'c> = | Success of 'c * State<'a, 'b> | Failure of string * State<'a, 'b> type Parser<'a,'b, 'c> = State<'a, 'b> -> Result<'a, 'b, 'c> let (>>=) left right state = match left state with | Success (result, state) -> (right result) state | Failure (message, _) -> Result<'a, 'b, 'd>.Failure (message, state) let (<|>) left right state = match left state with | Success (_, _) as result -> result | Failure (_, _) -> right state let (|>>) parser transform state = match parser state with | Success (result, state) -> Success (transform result, state) | Failure (message, _) -> Failure (message, state) let (<?>) parser errorMessage state = match parser state with | Success (_, _) as result -> result | Failure (_, _) -> Failure (errorMessage, state) type ParseMonad() = member this.Bind (f, g) = f >>= g member this.Return x s = Success(x, s) member this.Zero () s = Failure("", s) member this.Delay (f:unit -> Parser<_,_,_>) = f() let parse = ParseMonad() 开放懒人列表 类型状态(输入:LazyList 让(>>=)左-右状态= 将左状态与 |成功(结果,状态)->(正确结果)状态F# 这是解析器组合器库的合理基础吗?,f#,parser-combinators,F#,Parser Combinators,我最近一直在与FParsec合作,我发现缺少泛型解析器是我的一个主要停止点。我对这个小库的目标是简单性以及对通用输入的支持。你能想出任何可以改善这一点的补充,或者有什么特别糟糕的吗 open LazyList type State<'a, 'b> (input:LazyList<'a>, data:'b) = member this.Input = input member this.Data = data type Result<'a, 'b, 'c>
|失败(message,824;)->Result我认为您需要做出的一个重要设计决策是您是否希望在解析器中支持回溯(我不太记得解析理论,但这可能指定了解析器可以处理的语言类型)
回溯。在您的实现中,解析器要么失败(失败案例),要么只生成一个结果(成功案例)。另一种选择是生成零个或多个结果(例如,将结果表示为
seqI,我正在考虑如何使用combine发挥我的优势。至于回溯,老实说,我还没有考虑过。我肯定会添加它并进行实验。感谢您的建议,一如既往,我很有洞察力。我只是检查了FParsec的实现,他们是有意的没有包括Combine
或ReturnFrom
方法。在这一个方法中,你是2对2。我已经实现了基本的回溯,我将在更好地理解它时对其进行优化。再次感谢。不知道是否有什么有用的,但也可能看到@Brian-老实说,这篇文章是我开始使用解析器组合器le的地方学习经验。:)
let (>>=) left right state =
seq {
for res in left state do
match res with
| Success(v, s) ->
let v =
right v s
|> List.tryFind (
fun res ->
match res with
| Success (_, _) -> true
| _ -> false
)
match v with
| Some v -> yield v
| None -> ()
} |> Seq.toList
let (<|>) left right state =
left state @ right state
let (>>=) left right state =
let rec readRight lst =
match lst with
| Cons (x, xs) ->
match x with
| Success (r, s) as q -> LazyList.ofList [q]
| Failure (m, s) -> readRight xs
| Nil -> LazyList.empty<Result<'a, 'b, 'd>>
let rec readLeft lst =
match lst with
| Cons (x, xs) ->
match x with
| Success (r, s) ->
match readRight (right r s) with
| Cons (x, xs) ->
match x with
| Success (r, s) as q -> LazyList.ofList [q]
| Failure (m, s) -> readRight xs
| Nil -> readLeft xs
| Failure (m, s) -> readLeft xs
| Nil -> LazyList.empty<Result<'a, 'b, 'd>>
readLeft (left state)
let (<|>) (left:Parser<'a, 'b, 'c>) (right:Parser<'a, 'b, 'c>) state =
LazyList.delayed (fun () -> left state)
|> LazyList.append
<| LazyList.delayed (fun () -> right state)
let! s1 = (str "ab" <|> str "a")
let! s2 = str "bcd"
member x.Combine(a, b) = a <|> b
member x.ReturnFrom(p) = p
let rec many p acc =
parser { let! r = p // Parse 'p' at least once
return! many p (r::acc) // Try parsing 'p' multiple times
return r::acc |> List.rev } // If fails, return the result