任何元组位置的简写F#

时间:2018-09-16 10:14:08

标签: f# tuples

F#中的以下模式是否有捷径,还是我可以毫不费力地创建一个独立于元组元素数量的模式?

 | (None, _, _,_,_) | (_,None,_,_,_) | (_,_,None,_,_) | (_,_,_,None,_) | (_,_,_,_,None)

模式的想法是在任何元素上使用None选项,以确保仅执行有效的计算。

2 个答案:

答案 0 :(得分:2)

如果所有5个元素都属于同一类型,则可以这样使用when子句:

| (None, _, _,_,_) | (_,None,_,_,_) | (_,_,None,_,_) | (_,_,_,None,_) | (_,_,_,_,None) -> "none!"

或者需要做很多辅助工作的时候:

module Tuple5 =
    let toArray (a, b, c, d, e) = [|a; b; c; d; e|]

当然,您需要为每个元组大小执行此操作。您将这样使用它:

| x when x |> Tuple5.toArray |> Array.contains None -> ()

但是,我从来不需要F#代码中的5个项目元组,其中所有项目都具有相同的类型。如果是这种情况,请考虑使用数组或列表而不是元组。

答案 1 :(得分:2)

如果您确实需要定期处理选项元组,那么反转逻辑并利用多案例活动模式可能会减轻痛苦。代替对任何位置的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