如何使用Active Pattern实现数学表达式简化

时间:2017-02-20 23:31:25

标签: f# symbolic-math

下面的简化函数试图简化类型
的数学表达式 ((2 + 3) * (2 + 4))

(2 * (3 + 4))

理想情况下,我想将匹配表达式写为:

| Product (Sum (c, a), Sum (c, b)) -> Product (c, Sum (a, b))

但是这给了我" c在这个模式中绑定两次"错误。所以我采取了守卫条件。

我想知道是否有更好的方法可以使用Active Patterns实现这一目标?

type Expr =
    | Number  of int
    | Sum     of Expr * Expr
    | Product of Expr * Expr

let rec eval =
    function
    | Number n       -> n
    | Sum (l, r)     -> eval l + eval r
    | Product (l, r) -> eval l * eval r

let rec show =
    function
    | Number n       -> n.ToString()
    | Sum (l, r)     -> "(" + show l + " + " + show r + ")"
    | Product (l, r) -> "(" + show l + " * " + show r + ")"

let rec simplify =
    function
    | Product (Sum (c, a), Sum (d, b)) when (c = d) -> Product (c, Sum (a, b))
    | Sum (l, r)     -> Sum (simplify l, simplify r)
    | Product (l, r) -> Product (simplify l, simplify r)
    | e -> e

let c = Product (Sum (Number 2, Number 3), Sum (Number 2, Number 4))
show c
eval c
show (simplify c)

1 个答案:

答案 0 :(得分:3)

我不确定活动模式是否更好,但它们在匹配语句中可以更具说明性,允许您分解每种情况。

这是一个使用活动模式的版本,我也在逻辑中做了修复。请注意它是多么冗长:

type Expr =
    | Number  of int
    | Sum     of Expr * Expr
    | Product of Expr * Expr

let rec eval =
    function
    | Number n       -> n
    | Sum (l, r)     -> eval l + eval r
    | Product (l, r) -> eval l * eval r

let rec show =
    function
    | Number n       -> n.ToString()
    | Sum (l, r)     -> "(" + show l + " + " + show r + ")"
    | Product (l, r) -> "(" + show l + " * " + show r + ")"

let (|CommonFactor|_|) =
   function
    | Sum (Product (a, b), Product (c, d)) when (a = c) -> Some <| Product (a, Sum (b, d))
    | Sum (Product (a, b), Product (c, d)) when (a = d) -> Some <| Product (a, Sum (b, c))
    | Sum (Product (a, b), Product (c, d)) when (b = c) -> Some <| Product (b, Sum (a, d))
    | Sum (Product (a, b), Product (c, d)) when (b = d) -> Some <| Product (b, Sum (a, c))
    | _ -> None

let (|Operation|_|) simplify =
   function
    | Sum (l, r)     -> Some <| Sum (simplify l, simplify r)
    | Product (l, r) -> Some <| Product (simplify l, simplify r)
    | _ -> None

let (|Constant|_|) =
    function
    | Number _ as n -> Some n
    | _ -> None

let rec simplify =
    function
    | CommonFactor exp -> simplify exp
    | Operation simplify exp -> exp
    | Constant exp -> exp
    | _ -> failwith "Oh teh noes!"

let c = Sum (Product (Number 2, Number 3), Product (Number 2, Number 4))
show c |> Dump
eval c |> Dump
show (simplify c) |> Dump