OCaml: Match expression inside another one?

后端 未结 2 1491
孤街浪徒
孤街浪徒 2020-12-24 05:18

I\'m currently working on a small project with OCaml; a simple mathematical expression simplifier. I\'m supposed to find certain patterns inside an expression, and simplify

相关标签:
2条回答
  • 2020-12-24 05:40

    Quick Solution

    You just need to add parentheses, or begin/end, around the inner match:

    let rec filter exp =
        match exp with
        | Var v -> Var v
        | Sum (e1, e2) -> Sum (e1, e2)
        | Prod (e1, e2) -> Prod (e1, e2)
        | Diff (e1, e2) ->
                (match e2 with
                 | Sum (e3, e4) -> filter (diffRule e2)
                 | Diff (e3, e4) -> filter (diffRule e2)
                 | _ -> filter e2)
        | Quot (e1, e2) ->
                (match e2 with
                 | Quot (e3, e4) -> filter (quotRule e2)
                 | Prod (e3, e4) -> filter (quotRule e2)
                 | _ -> filter e2)
    ;;
    

    Simplifications

    In your particular case there is no need for a nested match. You can just use bigger patterns. You can also eliminate the duplication in the nested rules using "|" ("or") patterns:

    let rec filter exp =
        match exp with
        | Var v -> Var v
        | Sum (e1, e2) -> Sum (e1, e2)
        | Prod (e1, e2) -> Prod (e1, e2)
        | Diff (e1, (Sum (e3, e4) | Diff (e3, e4) as e2)) -> filter (diffRule e2)
        | Diff (e1, e2) -> filter e2
        | Quot (e1, (Quot (e3, e4) | Prod (e3, e4) as e2)) -> filter (quotRule e2)
        | Quot (e1, e2) -> filter e2
    ;;
    

    You can make it even more readable by replacing unused pattern variables with _ (underscore). This also works for whole sub patterns such as the (e3,e4) tuple:

    let rec filter exp =
        match exp with
        | Var v -> Var v
        | Sum (e1, e2) -> Sum (e1, e2)
        | Prod (e1, e2) -> Prod (e1, e2)
        | Diff (_, (Sum _ | Diff _ as e2)) -> filter (diffRule e2)
        | Diff (_, e2) -> filter e2
        | Quot (_, (Quot _ | Prod _ as e2)) -> filter (quotRule e2)
        | Quot (_, e2) -> filter e2
    ;;
    

    In the same way, you can proceed simplifying. For example, the first three cases (Var, Sum, Prod) are returned unmodified, which you can express directly:

    let rec filter exp =
        match exp with
        | Var _ | Sum _ | Prod _ as e -> e
        | Diff (_, (Sum _ | Diff _ as e2)) -> filter (diffRule e2)
        | Diff (_, e2) -> filter e2
        | Quot (_, (Quot _ | Prod _ as e2)) -> filter (quotRule e2)
        | Quot (_, e2) -> filter e2
    ;;
    

    Finally, you can replace e2 by e and replace match with the function shortcut:

    let rec filter = function
        | Var _ | Sum _ | Prod _ as e -> e
        | Diff (_, (Sum _ | Diff _ as e)) -> filter (diffRule e)
        | Diff (_, e) -> filter e
        | Quot (_, (Quot _ | Prod _ as e)) -> filter (quotRule e)
        | Quot (_, e) -> filter e
    ;;
    

    OCaml's pattern syntax is nice, isn't it?

    0 讨论(0)
  • 2020-12-24 05:51

    You can make this terser (and I would argue clearer) by judicious use of underscores, as's and or-patterns. The resulting code is also more efficient, because it allocates less (in the Var, Sum and Prod cases)

    let rec filter = function
    | Var _ | Sum _ | Prod _ as e -> e
    | Diff (_, (Sum _ | Diff _) as e) -> filter (diffRule e)
    | Diff (_,e) -> e
    | Quot (_, (Quot _| Prod _) as e) -> filter (quoteRule e)
    | Quot (_,e) -> filter e
    ;;
    
    0 讨论(0)
提交回复
热议问题