f# - 以乘法优先级解析 "x y z"

标签 f# fparsec

我正在尝试使用 FParsec 在 F# 中编写 Mathematica 语言的解析器。

我为 MiniML 编写了一个,它支持具有高优先级的函数应用语法 f x y = (f(x))(y) 。现在我需要使用相同的语法来表示 f*x*y,因此具有与乘法相同的优先级。特别是,x y + 2 = x*y + 2x y ^ 2 = x * y^2

如何实现这一点?

最佳答案

正如 Stephan 在评论中指出的那样,您可以将运算符解析器拆分为两个单独的解析器,并将您自己的解析器放在中间以用于空格分隔的表达式。以下代码演示了这一点:

#I "../packages/FParsec.1.0.1/lib/net40-client"
#r "FParsec"
#r "FParsecCS"

open FParsec
open System.Numerics

type Expr =
  | Int of BigInteger
  | Add of Expr * Expr
  | Mul of Expr * Expr
  | Pow of Expr * Expr

let str s = pstring s >>. spaces
let pInt : Parser<_, unit> = many1Satisfy isDigit |>> BigInteger.Parse .>> spaces
let high = OperatorPrecedenceParser<Expr,unit,unit>()
let low = OperatorPrecedenceParser<Expr,unit,unit>()
let pHighExpr = high.ExpressionParser .>> spaces
let pLowExpr = low.ExpressionParser .>> spaces

high.TermParser <-
  choice
    [ pInt |>> Int
      between (str "(") (str ")") pLowExpr ]

low.TermParser <-
  many1 pHighExpr |>> (function [f] -> f | fs -> List.reduce (fun f g -> Mul(f, g)) fs) .>> spaces

low.AddOperator(InfixOperator("+", spaces, 10, Associativity.Left, fun f g -> Add(f, g)))
high.AddOperator(InfixOperator("^", spaces, 20, Associativity.Right, fun f g -> Pow(f, g)))

run (spaces >>. pLowExpr .>> eof) "1 2 + 3 4 ^ 5 6"

输出为:

Add (Mul (Int 1,Int 2),Mul (Mul (Int 3,Pow (Int 4,Int 5)),Int 6))

如预期的那样表示 1 * 2 + 3 * 4^5 * 6

关于f# - 以乘法优先级解析 "x y z",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29322892/

相关文章:

debugging - 如果我不花很多时间调试,做 TDD 有意义吗?

.net - F# 的简单包装器,用于执行矩阵运算

entity-framework - F# 中的 Entity Framework 身份管理

f# - 解析为递归数据结构

parsing - FParsec 在可选解析器上失败

recursion - 递归较少的函数式编程?

f# - 检测 FParsec 何时未解析所有输入

f# - 使用 FParsec 解析分隔列表

f# - 如何解析 FParsec 中的递归语法

visual-studio - 转到 F# 库的定义