2016-12-13 5 views
6

は、F#でオプションタイプです:オプションの種類が崩壊しますか?ここ

type Option<'a> = 
    | Some of 'a 
    | None 

は、私がOptionOptionがあるとします。

type Option2<'a> = 
    | O of Option<'a> 
    | None 

それはちょうど1 Optionまで崩壊しますしていますか?

+2

いいえ、それはしません。それは本当に奇妙な行動でしょう。また、最初のケースには名前がないため、2番目の定義はコンパイルされません。 –

+2

お試しあればどうなりますか? –

+2

FWIWでは、* bind *: 'Some(Some 42)|> Option.bind id'で通常の' option'値を 'Some 42'に簡単に '平坦化'できます。 –

答えて

5

いいえ、F#は公称タイプのシステムです。 構造的に相当のタイプは互換性がありません。したがって、OptionOption2が全く同じ(名前を除いて)あっても、これらのタイプは異なります。あなたの場合は、intのリストとintのリストのリストが同じかどうかを尋ねるのと同じように異なります。

let hasOptionType (_ : Option<_>) =() 
let hasOption2Type (_ : Option2<_>) =() 

let o = Option.None 
let o2 = Option2.None 

hasOptionType o 
//hasOption2Type o // does not compile 
//hasOptionType o2 // does not compile 
hasOption2Type o2 

その仕事は、両方の方法けれどもあなたは、型の別名を持つことができます。

type IntOption = Option<int> 

let isOptionOfInt (_ : Option<int>) =() 
let isIntOption (_ : IntOption) =() 

let i = IntOption.None 
let i2 = Option<int>.None 

isOptionOfInt i 
isOptionOfInt i2 
isIntOption i 
isIntOption i2 
1

いいえ、あなたが定義したオプションの種類を自動的に他のいくつかのタイプにマージされることはありません。彼らは別々の弁別された組合であり、そのように扱われなければならない。

どのようにパターンマッチしなければならないとOption2の値を構築示しており、以下の例を見てみましょう:あなたはOptionOptionについて話すが、その後のタイプを示しているため、あなたの質問は少し混乱して

let info x = match x with 
      | O (Some i) -> sprintf "Found %d" i 
      | O (Option.None) -> "The wrapping Option2 contained None" 
      | Option2.None -> "The wrapper was None" 

System.Console.WriteLine(info (O (Some 3))) 
System.Console.WriteLine(info (O Option.None)) 
System.Console.WriteLine(info Option2.None) 

// prints: 
// Found 3 
// The wrapping Option2 contained None 
// The wrapper was None 
4

Optionを含むあなた自身のOption2タイプです。

私はあなたの質問が本当にこれと仮定します:Some (Some x)Some xに崩壊しますか?

その答えはいいえです。その崩壊は暗黙的に型を変更し、Optionが提供する型の安全性の一部を失うことになります。また、折りたたまれたバージョンと折りたたまれていないバージョンの区別は重要です。この例を考えてみましょう。

match List.tryHead [Some 1; None; Some 2] with 
| Some (Some x) -> sprintf "The first item exists with a value of %i" x 
| Some None  -> "The first item exists but it has no value" 
| None   -> "The list was empty" 

List.tryHead関数はリストの最初の要素を返します。リストが空の場合はNoneを返します。 Option<int>のリストを渡していますので、返す値はOption<Option<int>>

戻り値の型が異なる可能性のあるすべてのケースをカバーするために、戻り値を照合することができます。これらのケースを別々に扱いたい場合には、これは便利です。

しかし、我々はまだ同等としてSome NoneNoneを治療する能力を持っている:

match List.tryHead [Some 1; None; Some 2] with 
| Some (Some x) -> sprintf "The first item exists with a value of %i" x 
| _    -> "No value found" 
関連する問題