在`match`表达式中寻找类似`let`的东西

时间:2018-02-02 18:41:52

标签: f#

有时我使用这样的东西:

match foo a with
| 1 -> printfn "%s" (foo a)
| 0 -> printfn "ok"

在这种情况下,我调用foo函数两次,如果是昂贵的调用,我使用此代码:

let tmp = foo a
match tmp with 
| 1 -> printfn "%s" tmp
| 0 -> printfn "ok"

但在这种情况下,我创建了具有外部范围的变量(关于match表达式)。

我正在寻找类似的东西:

match (foo a) as tmp with
| 1 -> printfn "%s" tmp
| 0 -> printfn "ok

在这种情况下你会用什么?有没有优雅的解决方案?

更新 - 真实示例:

let collection = getValuesFromDatabase a
match Array.length collection with 
| 0 -> printfn "nothing"
| _ -> bar collection.[0]

2 个答案:

答案 0 :(得分:6)

选项1:使用let-or do-block

let result =
    let tmp = foo a
    match tmp with
    | 1 -> printfn "%d" tmp
    | 0 -> printfn "ok"

将整个事物嵌套在let块下,不会使用tmp来污染命名空间。语法有点沉重,但作为回报,它允许本地计算的任意复杂性。

或者,如果您的结果是unit,则可以将let替换为do

do
    let tmp = foo a
    match tmp with
    | 1 -> printfn "%d" tmp
    | 0 -> printfn "ok"

选项2:使用模式别名

当模式匹配时,您可以同时匹配多个模式的值,将模式与&分开,例如:

match [1;2;3] with
| (x::_)&(_::y::_) -> printfn "First element is %d, second element is %d" x y

在这里,我使用两种模式匹配相同的列表:x::__::y::_。这个例子有点傻(我可能只是与x::y::_匹配),但它传达了这个想法。

在您的示例中,您可以使用此机制通过将其与简单模式匹配来捕获整个值:

 match foo a with
 | 1&x -> printfn "%d" x
 | 0 -> printfn "ok"

更新:"真实"示例

这是为了回应您的编辑,您提供了一个真实的"例如,它处理一个集合。

这"真实"例子实际上不同于"玩具"您之前提供的示例,您希望捕获collection,但您在Array.length collection上匹配 - 不一样。通常,除了如上所述将其置于嵌套的dolet块中之外,没有此快捷方式。但在你的具体情况下,我可以像这样重写比赛:

match getValuesFromDatabase a with 
| [||] -> printfn "nothing"
| xs -> bar xs.[0]

这里,我不是调用Array.length,而是将值与空数组匹配。这样,由于我匹配了集合本身,我可以在第二个匹配的情况下捕获它并使用它来获取第一个元素。

如果您想执行比空数组检查更复杂的检查,您还可以使用模式保护:

match getValuesFromDatabase a with 
| xs when Array.length xs = 0 -> printfn "nothing"
| xs -> bar xs.[0]

答案 1 :(得分:3)

在您的真实示例中,您可以使用if。在match闪耀的任何复杂数据类型上,您实际上并不是模式匹配。如果您正在测试集合是否为空,那么您可以编写如下内容:

let collection = getValuesFromDatabase a
if Array.length collection = 0 then printfn "nothing"
else bar collection.[0]
相关问题