2016-12-13 4 views
6

Вот тип опции в F #:Возможны ли варианты вариантов?

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

Пусть у меня есть Option из Option:

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

ли он получить рухнул вниз только один Option?

+2

Нет, это не так. Это было бы очень странное поведение. Кроме того, ваше второе определение не будет компилироваться, потому что в первом случае отсутствует имя. –

+2

Что произойдет, если вы попробуете? –

+2

FWIW, вы можете легко «сгладить» нормальные значения 'option' с помощью * bind *:' Some (Some 42) |> Option.bind id' становится 'Some 42'. –

ответ

5

Нет, F # имеет систему номинального типа . Структурно эквивалентные типы несовместимы. Так что даже если бы у вас были Option и Option2 точно такие же (кроме имени), эти типы были бы разными. Ваш случай отличается, аналогично тому, как список индексов и список списков индексов совпадают.

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:

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 в качестве Option, но затем показать тип который является вашим собственным Option2 типа, содержащего Option.

Я собираюсь предположить, что ваш вопрос действительно так: 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 None и None как равнозначные:

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" 
Смежные вопросы