enz*_*nzi 3 f# pattern-matching fsyacc
我是F#的新手,并不太熟悉整个模式匹配的想法.我试图找到一个更好的解决方案,但我担心我甚至无法正确表达问题 - 我希望问题标题至少有些准确.
我想要做的是从中提取2个"参数" listMethod.
listMethod是具有字符串和Expression"参数" 的几种类型之一(我怀疑参数是错误的术语):
let (varDecl, listExpr) =
match listMethod with
| Select (var, expr) -> (var, expr)
| Where (var, expr) -> (var, expr)
| Sum (var, expr) -> (var, expr)
| Concat (var, expr) -> (var, expr)
Run Code Online (Sandbox Code Playgroud)
然后我继续使用varDecl,最后有一个类似的匹配表达式与实际的listMethod代码,它使用我创建的几个临时变量varDecl.
我现在的问题是:如何使上述代码更紧凑?
我希望匹配所有具有2个参数(类型string和类型Expression)的类型,而不是自己列出它们,这有点丑陋且难以维护.
该ListMethod类型声明如下(整个事情是一个FsLex/FsYacc项目):
type ListMethod =
| Select of string * Expr
| Where of string * Expr
| Sum of string * Expr
| Concat of string * Expr
| ...
| somethingElse of Expr
Run Code Online (Sandbox Code Playgroud)
(截至目前我只有表格的类型string * Expr,但会改变).
我认为对于任何有经验的人来说,这是一个相当愚蠢的问题,但正如我所说,我是F#的新手并且自己无法找到解决方案.
提前致谢!
编辑: 我真的想避免列出所有可能类型的listMethod两次.如果我无法在match表达式中使用通配符或占位符,也许我可以修改listMethod类型以使事情更清晰.
想到的一个选项是仅listMethod创建一种类型并为具体类型创建第三个参数(Select,Where,Sum).还是有更好的方法?
这可能是标准方式:
let (varDecl, listExpr) =
match listMethod with
| Select (var, expr)
| Where (var, expr)
| Sum (var, expr)
| Concat (var, expr) -> (var, expr)
Run Code Online (Sandbox Code Playgroud)
该|标志的含义or,因此,如果这些比赛之一,其结果将被退回.只需确保每个案例都具有完全相同的名称(和类型).
正如Chuck评论的那样,这是一个更好的解决方案:
let (Select (varDecl, expr)
| Where (varDecl, expr)
| Sum (varDecl, expr)
| Concat (varDecl, expr)) = listMethod
Run Code Online (Sandbox Code Playgroud)
我认为对于任何有经验的人来说,这是一个相当愚蠢的问题,但正如我所说,我是F#的新手并且自己无法找到解决方案.
相反,这是一个非常好的问题,实际上是相对不受约束的,因为F#在这方面与其他语言不同(例如,你可以使用OCaml中的多态变体来解决这个问题).
正如Ankur所写,最好的解决方案始终是改变您的数据结构,以便在可能的情况下更轻松地完成您需要做的事情.KVB使用活动模式的解决方案不仅有价值而且新颖,因为该语言功能在其他语言中并不常见.Ramon建议使用or-patterns组合你的匹配案例也很好,但是你不想编写不完整的模式匹配.
也许在实践中出现的这个问题最常见的例子是运营商:
type expr =
| Add of expr * expr
| Sub of expr * expr
| Mul of expr * expr
| Div of expr * expr
| Pow of expr * expr
| ...
Run Code Online (Sandbox Code Playgroud)
您可以在哪里重构您的类型,如下所示:
type binOp = Add | Sub | Mul | Div | Pow
type expr =
| BinOp of binOp * expr * expr
| ...
Run Code Online (Sandbox Code Playgroud)
然后提取子表达式等任务:
let subExprs = function
| Add(f, g)
| Sub(f, g)
| Mul(f, g)
| Div(f, g)
| Pow(f, g) -> [f; g]
| ...
Run Code Online (Sandbox Code Playgroud)
可以更容易地执行:
let subExprs = function
| BinOp(_, f, g) -> [f; g]
| ...
Run Code Online (Sandbox Code Playgroud)
最后,不要忘记您可以使用OOP构造(例如实现共享接口)来扩充F#类型(例如union类型).这也可用于表达共性,例如,如果您对两种类型有两个重叠的要求,那么您可以使它们都实现相同的接口以暴露这种共性.