2015-04-23 69 views
3

我想寫一些函數,通過返回雙選項而不是雙打來處理錯誤。許多這些函數都會調用eachother,因此需要雙重選項作爲輸入以輸出其他雙重選項。問題是,我不能用雙選項做什麼,我可以用雙打來做 - 這很簡單,就像使用'+'添加它們一樣。F#選項類型執行計算

例如,一個函數將兩個雙精度分開,並返回一個double選項,其中none表示除零誤差。然後另一個函數調用第一個函數,並向它添加另一個雙重選項。

請告訴我是否有辦法做到這一點,或者我完全誤解了F#選項類型的含義。

+0

嘗試添加一些代碼示例,說明您要實現什麼,以及出現什麼錯誤 – Petr

+0

Some(1.0)+ Some(1.0)不起作用。如果它真的不起作用,那麼我不能真正使用它,因爲我有很多功能需要雙重選擇並返回雙重選項,並且他們都依靠彼此來做一些數學運算。 – user3685285

+1

你正在尋找的是一個選項工作流程。看看[這個線程](http://stackoverflow.com/questions/7818277/is-there-a-standard-option-workflow-in-f)。 – scrwtp

回答

9

這就是所謂的提升 - 你可以寫函數解除另一個函數在兩個選項:

let liftOpt f o1 o2 = 
     match (o1, o2) with 
     | (Some(v1), Some(v2)) -> Some(f v1 v2) 
     | _ -> None 

,那麼你可以提供應用例如功能:

let inline addOpt o1 o2 = liftOpt (+) o1 o2 
+1

你甚至可以進一步讓代碼更具可讀性:定義liftOpt就像在這裏完成的那樣,然後(這樣做*非常,非常非常本地*)用'let(+)o1 o2 = liftOpt(+)o1 o2'這樣的東西來映射'+'。現在你可以寫'let x,y =一些3.0,一些2.0',然後'x + y'。 –

+0

@DanielFabian良好的提示,偉大的地方(國際海事組織)要做到這一點將是提升'(+)'在'模塊選項',以擴大默認的'選項'。然後,只有在「打開選項」之後,您才能將範圍內的(+)提升 –

0

最後,我意識到我真正想要的是Option.get函數,它只需要一個'選項並返回'a。這樣,我可以模式匹配,並返回我想要的值。

2

liftA2如上所述將提供一種通用方法來將可用於參數double參數的任何函數「提升」到可在double option參數上工作的函數。

然而,在你的情況,你可能必須編寫特殊的功能你自己來處理你提到的邊緣情況

let (<+>) a b = 
    match (a, b) with 
    | (Some x, Some y) -> Some (x + y) 
    | (Some x, None) -> Some (x) 
    | (None, Some x) -> Some (x) 
    | (None, None)  -> None 

注意liftA2不會把您想在自動添加NoneSome(x)案件。

的鴻溝liftA2方法還需要一些特殊的處理,但其結構通常是什麼我們會自己寫

let (</>) a b = 
    match (a, b) with 
    | (Some x, Some y) when y <> 0.0d -> Some (x/y) 
    | _ -> None 

您可以使用這些功能,如

Some(2.0) <+> Some(3.0) // will give Some(5.0) 
Some(1.0) </> Some(0.0) // will give None 

而且,嚴格地說, lift被定義爲「高階函數」 - 這是一個函數並返回另一個函數的東西。

因此,這將是這個樣子:

let liftOpt2 f = 
    (function a b -> 
     match (a, b) with 
     | (Some (a), Some (b)) -> f a b |> Some 
     | _ -> None) 
0

在這種情況下,你可能要考慮Nullables以上選項,原因有二:

  • Nullables是值類型,而選項是參考類型。如果你有這些雙打的大集合,使用Nullables將把數字保留在堆棧上,而不是放在堆上,這可能會提高你的性能。
  • 微軟提供了一堆內置的Nullable Operators,它們可以讓你直接對空值執行數學運算,就像你試圖處理選項一樣。