F#类型构造函数不';Don’不要像函数一样工作

F#类型构造函数不';Don’不要像函数一样工作,f#,discriminated-union,F#,Discriminated Union,如果我定义这样的类型: type Foo = Items of seq<int> > type Foo = Items of seq<int>;; > Items;; val it : arg0:seq<int> -> Foo = <fun:clo@18-5> > let length (ints: int seq) = Items ints;; > length;; val it : (seq<int>

如果我定义这样的类型:

type Foo = Items of seq<int>
> type Foo = Items of seq<int>;;
> Items;;
val it : arg0:seq<int> -> Foo = <fun:clo@18-5>

> let length (ints: int seq) = Items ints;;
> length;;
val it : (seq<int> -> Foo) = <fun:it@20-3>
但是,以下操作不起作用:

[1;2;3] |> Items
错误消息是:

Type mismatch. Expecting a
    int list -> 'a    
but given a
    seq<int> -> Foo

这与其说是答案,不如说是猜测,但我怀疑这个问题可能与C#中的类似行为有关,因为构造函数不能有类型参数。默认情况下,我的理解是F#函数是完全泛型的,只有通过类型注释和推理才能变得专门化。如果构造函数不能拥有类型参数通常是在CLR或.NET中烘焙出来的,那么它可以解释为什么F#type构造函数在默认情况下不能遵循与函数相同的泛型行为。

这是一个协方差问题。 类型构造函数函数
Items
seq->Items
,但是给出了一个
列表,您必须显式地向上转换,因为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

如果将代码更改为如下所示:

type Foo = Items of seq<int>
> type Foo = Items of seq<int>;;
> Items;;
val it : arg0:seq<int> -> Foo = <fun:clo@18-5>

> let length (ints: int seq) = Items ints;;
> length;;
val it : (seq<int> -> Foo) = <fun:it@20-3>
>类型Foo=序号的项目;;
>项目;;
val it:arg0:seq->Foo=
>let length(整数:整数序列)=项目整数;;
>长度;;
val it:(seq->Foo)=

这个问题变得更加明显。几乎相同的类型签名,但仍然存在相同的问题。我敢肯定,使用构造函数作为一级函数是一个错误。

使用构造函数作为一级函数是一个相当新的功能(好吧,不是那么新,但仍然如此)。看见这可能是个bug。好的。有人知道如何向微软的F#团队报告bug吗?@jpierson-事实上,我认为这是解决一般语言问题的正确方法。您的链接将适用于在一个平台上看到的问题,而不是在另一个平台上看到的问题。@kvb-好的,我假设VisualSharp主要是Microsoft内部的问题,如Visual Studio的工具,而不是更一般的问题,如编译错误。也许你是对的。在我给出的其他示例中,F#会自动进行子类型转换。我想知道为什么这种情况会有不同的表现。
>type Foo=Items of seq;;>项目;;val it:arg0:seq->Foo=
let length(ints:int seq)=seq.length ints>let length(ints:int seq)=Items ints;;>长度;;valit:(seq->Foo)=
相同类型的签名,但仍然存在相同的问题。“我很确定这是一个错误。”mydogisbox同意。由于类型推断问题,他们可能有意保持构造函数的严格性。值得提交一个问题来确认。有工作要扩展自动铸造,但目前还不包括这个案例。下面是唐·赛姆对此的评论:好的观点。我报告这是一个错误。让我们看看他们是怎么说的。
type Foo=Items of seq;;让项目=项目;;[1;2;3]|>项目也可以工作,这是同样的事情。我相信我上面的假设是正确的,那么C#中经常使用的解决方法也可以在F#中工作,在类型上创建一个静态工厂方法,然后根据需要使用必要的类型参数调用构造函数。