构造值初始化

Rus*_*tam 3 f#

我从F#开始,我无法理解构造值初始化的最佳方法是什么:

let x = TryCalculateX() // for example, searching in DB
if x = null then
    // for example, we create it ourself and out it into DB
    let x = TryAnotherCalcultaion() 
    someProcessing x // x is now initialized => Ok
someProcessing x // here I use old, not initialized x! => Fails
Run Code Online (Sandbox Code Playgroud)

你如何处理类似的情况?

UPD.我设计的最好的是:

let getX() =
    let res = TryCalculateX() 
    if res = null then
        let res = TryAnotherCalcultaion() 
        res
    else
        res
Run Code Online (Sandbox Code Playgroud)

这不是很酷,恕我直言

Upd 2. @ChaosPandion提出了很好的解决方案:

let x = 
    match TryCalculateX() with
    | null -> TryAnotherCalculation() 
    | x -> x
someProcessing x
Run Code Online (Sandbox Code Playgroud)

但是如果添加一个额外的嵌套级别,这也变得不是很好:

let x = 
    match TryCalculateX() with
    | null -> 
        match TryAnotherCalculation()  with
        | null -> OneMoreCalculation()
        | y -> y
    | x -> x
someProcessing x
Run Code Online (Sandbox Code Playgroud)

也许有一些更普遍的模式适用?

更新3.再次感谢@ChaosPandion,这是一个通用的解决方案:

// Different initialization strategies
let x() = printfn("x"); None
let y() = printfn("y"); None
let z() = printfn("z"); Some(1)

// Sequence of strategies
let a = seq { 
    yield x()
    yield y()
    yield z()
}

// Initializing function
let init what = Seq.find (fun el -> Option.isSome el) what

// Initializing
let b = init a
Run Code Online (Sandbox Code Playgroud)

F#交互式打印:

xyz ... val b:int option = 1

Cha*_*ion 5

以下是一个很好的约定.它可以使用,null但我会建议返回一个'a option类型.

选项

let x = 
    match TryCalculateX() with
    | Some x -> x
    | None -> TryAnotherCalculation() 
someProcessing x
Run Code Online (Sandbox Code Playgroud)

空值

let x = 
    match TryCalculateX() with
    | null -> TryAnotherCalculation() 
    | x -> x
someProcessing x
Run Code Online (Sandbox Code Playgroud)

序列

假设你写了每次返回的尝试,option那么你可以编写一个优雅的尝试序列.

let x = seq {
            yield firstTry ()
            yield secondTry ()
            yield thirdTry ()
            yield sensibleDefault
        } |> Seq.pick id
someProcessing x
Run Code Online (Sandbox Code Playgroud)