gpt4 book ai didi

parsing - FParsec 中的递归语法

转载 作者:行者123 更新时间:2023-12-03 16:00:59 27 4
gpt4 key购买 nike

我决定查看 FParsec,并尝试为 λ 表达式编写解析器。事实证明,渴望使递归解析变得困难。我该如何解决这个问题?

代码:

open FParsec

type λExpr =
| Variable of char
| Application of λExpr * λExpr
| Lambda of char * λExpr

let rec FV = function
| Variable v -> Set.singleton v
| Application (f, x) -> FV f + FV x
| Lambda (x, m) -> FV m - Set.singleton x

let Λ0 = FV >> (=) Set.empty

let apply f p =
parse
{ let! v = p
return f v }

let λ e =

let expr, exprR = createParserForwardedToRef()

let var = lower |> apply Variable

let app = tuple2 expr expr
|> apply Application

let lam = pipe2 (pchar 'λ' >>. many lower)
(pchar '.' >>. expr) (fun vs e ->
List.foldBack (fun c e -> Lambda (c, e)) vs e)

exprR := choice [
lam
app
var
(pchar '(' >>. expr .>> pchar ')')
]

run expr e

谢谢!

最佳答案

正如您所指出的,问题在于您的应用程序解析器递归调用 expr ,因此存在无限循环。需要编写解析器,以便它始终消耗一些输入,然后决定要做什么。

在 lambda 演算的情况下,棘手的事情是识别应用程序和变量,因为如果您有类似 x... 的输入那么第一个字符表明它可能是其中之一。

您可以像这样合并应用程序和变量的规则:

let rec varApp = parse {
let! first = lower |> apply Variable
let! res =
choice [ expr |> apply (fun e -> Application(first, e))
parse { return first } ]
return res }

这首先解析一个变量,然后解析另一个表达式(在这种情况下它是一个应用程序),或者它只返回变量(如果变量后面没有表达式)。其余规则类似:
and lam = 
pipe2 (pchar 'λ' >>. many lower)
(pchar '.' >>. expr) (fun vs e ->
List.foldBack (fun c e -> Lambda (c, e)) vs e)
and brac = pchar '(' >>. expr .>> pchar ')'
and expr = parse.Delay(fun () ->
choice
[ lam; varApp; brac ])

我只是通过使用 parse.Delay() 避免了显式突变的需要(这使得创建递归值引用成为可能)。原则上可以写成:
and expr = parse {
return! choice [ lam; varApp; brac ] }

...但出于某种原因,FParsec 没有实现 ReturnFrom如果您想使用 return! 所需的成员在计算表达式中。

关于parsing - FParsec 中的递归语法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6186230/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com