如何重写多级匹配表达式

时间:2018-01-02 18:52:27

标签: f#

我有返回a' option类型的函数。我的功能看起来像:

let foo(a) = 
   match fooB a.F1 with
   | Some(b) -> match fooC b.F2 with
                | Some(c) -> match fooD c.F3 with 
                             | Some(d) -> match fooE d.F4 with 
                                          // ......
                             | None -> ()
                | None -> ()
    | None -> ()

是否有任何功能模式可以避免这种多级match expressions

3 个答案:

答案 0 :(得分:11)

看起来像你正在寻找的是Option.bind

let foo(a) = 
    fooB a.F1 
    |> Option.bind(fun b -> fooC b.F2)
    |> Option.bind(fun c -> fooD c.F3)
    |> Option.bind(fun d -> fooE d.F4)

Option.bind基本上等同于

// ('a -> 'b option) -> 'a option -> 'b option
let bind f m =
    match m with
    | Some x -> f x
    | _ -> None

答案 1 :(得分:4)

函数式编程可以利用monadic操作,特别是bind运算符。以下是Maybe monad在Haskell上使用的说明,但与F#' s Option类型相同。

幸运的是,bind运算符几乎是预定义的:

let (>>=) ma f = Option.bind f ma

let foo a = 
    fooB a.F1
    >>= fun b -> fooC b.F2 
    >>= fun c -> fooD c.F3 
    >>= fun d -> fooE d.F4
    // ...

答案 2 :(得分:0)

另一种选择是为Option类型创建一个Computation Expression Builder,利用Option.bind函数。

type OptionBuilder() =
    member __.Bind (opt,map) = Option.bind map opt
    member __.Return value = Some value
    member __.ReturnFrom (opt: Option<_>) = opt
    member __.Zero () = Some ()

let option = OptionBuilder()

然后,您可以通过一次option计算完成所有工作:

let foo a =
    option {
        let! b = fooB a.F1
        let! c = fooC b.F2
        let! d = fooD c.F3
        return! fooE d.F4
    }

如果所有选项均为Some,则会返回d.F4 Some,否则会返回None