2015-11-20 2 views
1

Эта функция имеет подпись: (UnionCaseInfo -> bool) -> 'T optionПочему здесь требуется аннотация?

let private findCase<'T> f = 
    match FSharpType.GetUnionCases typeof<'T> |> Array.filter f with 
     |[|case|] -> Some (FSharpValue.MakeUnion(case,[||]) :?> 'T) 
     |_ -> None 

Эта функция, которая вызывает описанную выше функцию, имеет подпись: int -> obj

let CreateFromId<'T> id = 
    match findCase (fun case -> case.Tag = id) with 
     | Some c -> c 
     | None -> failwith (sprintf "Lookup for union case by \"%d\" failed." id) 

В шаблон для CreateFromId, IntelliSense показывает, что c выводится на иметь тип obj, даже если он показывает правильную подпись для findCase. Почему тип кажется «потерянным» в шаблоне?

(я могу обойти это, указав тип возвращаемого CreateFromId к 'T)

ответ

1

Поскольку параметр типа 'T не упоминается в теле функции, поэтому тип логического вывода не имеет никакого способа знать ваше намерение было наименование 'T возвращение type.

Таким образом, вы можете добавить его в организме в качестве возвращаемого типа (как вы уже догадались) или удалить его из объявления:

let CreateFromId id = ... 

Удалив это работает, потому что F # делает автоматическое обобщение, то только другое - это будет использовать произвольное имя для переменной типа, но даже если вы хотите назвать эту переменную типа T, я бы добавил ее как возвращаемый тип, но нет в декларации между скобками:

let CreateFromId id : 'T = ... 
+0

Это имеет смысл. Я думаю, что мне нужно иметь параметр типа, потому что это требует «FSharpType.GetUnionCases». –

0

Тип CreateFromId был i nferred на int -> obj, потому что нет ничего, «связывающего» два аргумента типа 'T с вашими функциями.

findCase является надлежащим образом общим по 'T, но CreateFromId объявлен как общий, а аргумент общего типа никогда не используется.

Аннотирование функции с требуемым типом является достаточно хорошим, чтобы типы были расположены вверх. Вы также можете позвонить findCase явно предоставляя типа:

let CreateFromId<'T> id = 
    match findCase<'T> (fun case -> case.Tag = id) with 
    | Some c -> c 
    | None -> failwith (sprintf "Lookup for union case by \"%d\" failed." id) 

Или, как говорит другой ответ, просто перенесите 'T от CreateFromId и пусть умозаключение типа делать свое дело.

Смежные вопросы