Ocaml:匹配表达式在另一个? [英] Ocaml: Match expression inside another one?
问题描述
- 将表单a - (b + c)或类似的所有表达式转换为a - b - c
- 将表单a /(b * c)或类似的所有表达式转换为/ b / c
我怀疑这将是相当简单的,一旦我设法实现一个,我可以轻松地实现另一个。但是,我有递归模式匹配功能的麻烦。我的类型表达是这样的:
type expr =
|字符串的变量(*变量*)
| expr的总和* expr(* sum *)
| expr的差异* expr(*差异*)
| expr * expr(* product *)的生成
| expr * expr(*商*)
;;
我主要遇到麻烦,是在匹配表达式中。例如,我正在尝试这样的事情:
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)→>
匹配e2与
| Sum(e3,e4) - > filter(diffRule e2)
| Diff(e3,e4)→> filter(diffRule e2)
| _ - >过滤器e2
| Quot(e1,e2) - > ***这行***
匹配e2与
| Quot(e3,e4) - >过滤器(quotRule e2)
| Prod(e3,e4)→>过滤器(quotRule e2)
| _ - >过滤器e2
;;
然而,标记行上的匹配表达式似乎被认为是之前的一部分内匹配而不是主匹配,所以所有的Quot(...)表达式永远不会被识别。甚至可以在这样的其他匹配表达式中匹配表达式吗?那么结束内线比赛的正确方法是什么呢?所以我可以继续匹配其他的可能性?
忽略逻辑,因为我几乎想到了第一个只是我没有能够尝试,因为我必须首先处理这个匹配错误,虽然任何关于如何处理递归或逻辑的建议将是欢迎的。
快速解决方案
您只需要添加括号(或开始
/ 结束
)内部匹配:
let rec filter exp =
match exp with
| Var v - > Var v
| Sum(e1,e2) - > Sum(e1,e2)
| Prod(e1,e2) - > Prod(e1,e2)
| (e3,e4) - > filter(diffRule e2)
| Diff(e3,e4) - > filter e4) - > filter(diffRule e2)
| _ - > filter e2 )
| Quot(e1,e2) - >
(匹配e2与
| Quot(e3,e4) - > filter(quotRule e2)
| Prod(e3,e4) e2)
| _ - > filter e2)
;;
简化
在你的具体情况下不需要一个嵌套的比赛。
您只能使用更大的模式。您也可以使用 |
(或)模式消除嵌套规则中的重复:
让rec filter exp =
匹配exp与
| Var v - > Var v
| Sum(e1,e2) - > Sum(e1,e2)
| Prod(e1,e2) - > Prod(e1,e2)
| Diff(e1,(Sum(e3,e4)| Diff(e3,e4)为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
;;
您可以通过将 _
(下划线)。
这也适用于整个子模式,如(e3,e4)
tuple:
让rec filter exp =
匹配exp与
| 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
;;
以同样的方式,您可以继续简化。例如,前三种情况( Var
, Sum
, Prod
)被返回未修改,您可以直接表达:
let rec filter exp =
match exp with
| Var _ | Sum _ |作为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
;;
最后,您可以将 e2
code> e 并将匹配
替换为功能
快捷方式:
let rec filter = function
| Var _ | Sum _ |作为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的模式语法很好,不是吗?
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 them so the number of parenthesis inside the expression decreases. So far I've been able to implement most rules except two, for which I've decided to create a recursive, pattern-matching "filter" function. The two rules I need to implement are:
-Turn all expressions of the form a - (b + c) or similar into a - b - c
-Turn all expressions of the form a / (b * c) or similar into a / b / c
...which I suspect would be fairly simple, and once I've managed to implement one, I can implement the other easily. However, I'm having trouble with the recursive pattern-matching function. My type expression is this:
type expr =
| Var of string (* variable *)
| Sum of expr * expr (* sum *)
| Diff of expr * expr (* difference *)
| Prod of expr * expr (* product *)
| Quot of expr * expr (* quotient *)
;;
And what I'm mainly having trouble on, is in the match expression. For example, I'm trying something like this:
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) -> ***this line***
match e2 with
| Quot(e3, e4) -> filter (quotRule e2)
| Prod(e3, e4) -> filter (quotRule e2)
| _ -> filter e2
;;
However, it seems that the match expression on the marked line is being recognized as being part of the previous "inner match" instead of the "principal match", so all "Quot(...)" expressions are never recognized. Is it even possible to have match expressions inside other match expressions like this? And what would be the correct way to end the inner match so I can continue matching the other possibilities?
Ignore the logic, since it's pretty much what I came up with first, it's just that I haven't been able to try it since I have to deal with this "match" error first, although any recommendation on how to handle the recursiveness or the logic would be welcome.
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?
这篇关于Ocaml:匹配表达式在另一个?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!