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

dem*_*mas 0 f#

有时我使用这样的东西:

match foo a with
| 1 -> printfn "%s" (foo a)
| 0 -> printfn "ok"
Run Code Online (Sandbox Code Playgroud)

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

let tmp = foo a
match tmp with 
| 1 -> printfn "%s" tmp
| 0 -> printfn "ok"
Run Code Online (Sandbox Code Playgroud)

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

我正在寻找这样的东西:

match (foo a) as tmp with
| 1 -> printfn "%s" tmp
| 0 -> printfn "ok
Run Code Online (Sandbox Code Playgroud)

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

更新 - 真实的例子:

let collection = getValuesFromDatabase a
match Array.length collection with 
| 0 -> printfn "nothing"
| _ -> bar collection.[0]
Run Code Online (Sandbox Code Playgroud)

Fyo*_*kin 6

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

let result =
    let tmp = foo a
    match tmp with
    | 1 -> printfn "%d" tmp
    | 0 -> printfn "ok"
Run Code Online (Sandbox Code Playgroud)

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

或者,如果您的结果是a unit,则可以替换letdo:

do
    let tmp = foo a
    match tmp with
    | 1 -> printfn "%d" tmp
    | 0 -> printfn "ok"
Run Code Online (Sandbox Code Playgroud)

选项2:使用模式别名

在模式匹配时,您可以一次匹配多个模式的值,将模式与&例如:

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

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

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

 match foo a with
 | 1&x -> printfn "%d" x
 | 0 -> printfn "ok"
Run Code Online (Sandbox Code Playgroud)

更新:"真实"的例子

这是为了响应您的编辑,您提供了一个"真实"示例,用于处理集合.

这个"真实"的例子实际上与你之前提供的"玩具"示例有所不同,你想要捕捉collection,但是你匹配Array.length collection- 不是同一件事.通常,除了将其置于如上所述的嵌套dolet块中之外,没有其他快捷方式.但在你的具体情况下,我可以像这样重写匹配:

match getValuesFromDatabase a with 
| [||] -> printfn "nothing"
| xs -> bar xs.[0]
Run Code Online (Sandbox Code Playgroud)

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

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

match getValuesFromDatabase a with 
| xs when Array.length xs = 0 -> printfn "nothing"
| xs -> bar xs.[0]
Run Code Online (Sandbox Code Playgroud)