【问题标题】:How to implement math expression simplification using Active Pattern如何使用 Active Pattern 实现数学表达式简化
【发布时间】:2017-02-20 23:31:24
【问题描述】:

下面的简化函数试图简化类型的数学表达式
((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)

【问题讨论】:

  • 你的方式是正确的,没有更短的符号。
  • 您如何将等于30(2 + 3) * (2 + 4)“简化”为等于142 * (3 + 4)?这些东西是不等价的。
  • "Expert F# 4.0" 有一个关于 Simplifying Algebraic Expressions 的部分可能会有所帮助。
  • 您可以下载"Expert F# 4.0"的源代码
  • @TheInnerLight - 你是对的 :)

标签: f# symbolic-math


【解决方案1】:

我不确定主动模式是否更好,但它们可以在 match 语句中更具声明性,让您可以拆分每种情况。

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

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

【讨论】:

  • 谢谢,这正是我想要的。顺便说一句,什么是转储。
  • 我使用的是 LinqPad,所以基本上可以打印出来
猜你喜欢
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 2012-04-08
  • 1970-01-01
  • 1970-01-01
  • 2011-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多