Если вам действительно нужно иметь дело с опциональными кортежами на регулярной основе, инвертирование логики и использование нескольких вариантов активного паттерна может облегчить боль. Вместо проверки None
в любой позиции, проверьте Some
во всех положениях.
let (|AllSome5|AnyNone5|) = function
| Some(a), Some(b), Some(c), Some(d), Some(e) -> AllSome5(a, b, c, d, e)
| _ -> AnyNone5
// val ( |AllSome5|AnyNone5| ) :
// 'a option * 'b option * 'c option * 'd option * 'e option ->
// Choice<('a * 'b * 'c * 'd * 'e),unit>
match Some(42), Some(1.0), Some(0uy), Some("abc"), Some('d') with
| AllSome5(a, b, c, d, e) -> () // do something with 42, 1.0, 0uy, "abc", 'd'
| AnyNone5 -> () // otherwise
Достижение независимости от размера кортежа технически не невозможно, но это не красиво. Перегрузка метода в сочетании со статически разрешенными параметрами типа не будет использоваться в качестве активного шаблона, но вместо этого потребуется вызов функции.
let some4 = function
| Some(a), Some(b), Some(c), Some(d) -> Some(a, b, c, d)
| _ -> None
let some5 = function
| Some(a), Some(b), Some(c), Some(d), Some(e) -> Some(a, b, c, d, e)
| _ -> None
type Foo = Foo with
static member($) (_ : Foo, (a, b, c, d)) = some4(a, b, c, d)
static member($) (_ : Foo, (a, b, c, d, e)) = some5(a, b, c, d, e)
let inline foo args = Foo $ args
match foo(Some(42), Some(1.0), Some(0uy), Some("abc"), Some('d')) with
| Some(a, b, c, d, e) -> () // do something with 42, 1.0, 0uy, "abc", 'd'
| None -> () // otherwise