Reputation: 45295
Sometimes I use something like this:
match foo a with
| 1 -> printfn "%s" (foo a)
| 0 -> printfn "ok"
In this case I call foo
function twice and if it is expensive call I use this code:
let tmp = foo a
match tmp with
| 1 -> printfn "%s" tmp
| 0 -> printfn "ok"
But in this case I have created variable with outer scope (regarding match
expression).
I am looking for something like this:
match (foo a) as tmp with
| 1 -> printfn "%s" tmp
| 0 -> printfn "ok
What do you use in this cases ? Is there any elegant solution ?
Update - real example:
let collection = getValuesFromDatabase a
match Array.length collection with
| 0 -> printfn "nothing"
| _ -> bar collection.[0]
Upvotes: 0
Views: 95
Reputation: 243051
In your real example, you can just use if
. You are not really pattern matching on any complex data type which is where match
shines. If you're testing whether a collection is empty, you can just write something like:
let collection = getValuesFromDatabase a
if Array.length collection = 0 then printfn "nothing"
else bar collection.[0]
Upvotes: 3
Reputation: 80744
let result =
let tmp = foo a
match tmp with
| 1 -> printfn "%d" tmp
| 0 -> printfn "ok"
Nesting the whole thing under a let
-block keeps from polluting the namespace with tmp
. The syntax is a bit heavy, but in return it allows for arbitrary complexity of the local computation.
Alternatively, if your result is a unit
, you can replace let
with do
:
do
let tmp = foo a
match tmp with
| 1 -> printfn "%d" tmp
| 0 -> printfn "ok"
When pattern-matching, you can match a value with more than one pattern at once, separating the patterns with &
, e.g.:
match [1;2;3] with
| (x::_)&(_::y::_) -> printfn "First element is %d, second element is %d" x y
Here, I am matching the same list with two patterns: x::_
and _::y::_
. The example is a bit silly (I could have just matched with x::y::_
), but it conveys the idea.
In your example, you can use this mechanism to capture the whole value by matching it with a trivial pattern:
match foo a with
| 1&x -> printfn "%d" x
| 0 -> printfn "ok"
This is in response to your edit, where you provided a "real" example, which deals with a collection.
This "real" example is actually different from the "toy" examples that you provided before, in that you want to capture collection
, but you're matching on Array.length collection
- not the same thing. In general, there is no shortcut for this, except putting it in a nested do
or let
block as described above. But in your specific case I could rewrite the match like this:
match getValuesFromDatabase a with
| [||] -> printfn "nothing"
| xs -> bar xs.[0]
Here, instead of calling Array.length
, I match the value with an empty array. This way, since I'm matching the collection itself, I can capture it in the second match case and use it to get the first element.
If you wanted to perform a more complex check than just the empty array check, you could also use a pattern guard:
match getValuesFromDatabase a with
| xs when Array.length xs = 0 -> printfn "nothing"
| xs -> bar xs.[0]
Upvotes: 6