Конструктор типа F # не действует как функция
Если я определяю такой тип:
type Foo = Items of seq<int>
Я могу создать Foo
следующим образом:
Items [1;2;3]
Однако следующее не работает:
[1;2;3] |> Items
Сообщение об ошибке:
Type mismatch. Expecting a
int list -> 'a
but given a
seq<int> -> Foo
Разве компилятор не может преобразовать int list
в seq<int>
? Если конструктор Items
был нормальной функцией, я мог бы вызвать его в любом случае:
let length ints = Seq.length ints
printfn "%A" (length [1;2;3])
printfn "%A" ([1;2;3] |> length)
Ответы
Ответ 1
Это ковариационная проблема.
Функция конструктора типов Items
равна seq<int> -> Items
, но ей присваивается List<int>
, который вам придется явно понижать, поскольку F # не выполняет автоматическое преобразование подтипа.
type Foo = Items of int list
[1;2;3] |> Items //compiles
или используйте соответствующий модуль
type Foo = Items of int seq
[1;2;3] |> Seq.ofList |> Items //compiles
Ответ 2
Это скорее предположение, чем ответ, но я подозреваю, что проблема может быть связана с аналогичным поведением на С# в том, что конструкторы не могут иметь параметры типа. По умолчанию я понимаю, что функции F # являются полностью родовыми и становятся специализированными только для аннотаций и выводов типов. Если неспособность конструкторов иметь параметры типа - это что-то, что запекается в CLR или .NET вообще, то это может объяснить, почему конструкторы типа F # не могут следовать этому же родовому по умолчанию, как это делается для функций.
Ответ 3
Если вы измените свой код так:
> type Foo = Items of seq<int>;;
> Items;;
val it : arg0:seq<int> -> Foo = <fun:[email protected]>
> let length (ints: int seq) = Items ints;;
> length;;
val it : (seq<int> -> Foo) = <fun:[email protected]>
Проблема становится еще более очевидной. Почти идентичная подпись типа, но все та же проблема. Я уверен, что это ошибка с использованием конструкторов в качестве первоклассных функций.