【问题标题】:F# type constructor doesn't act like a functionF# 类型构造函数不像函数
【发布时间】:2017-06-18 18:39:54
【问题描述】:

如果我定义这样的类型:

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&lt;int&gt;?如果Items 构造函数是一个普通函数,我可以用任何一种方式调用它:

let length ints = Seq.length ints
printfn "%A" (length [1;2;3])
printfn "%A" ([1;2;3] |> length)

【问题讨论】:

  • 使用构造函数作为一等函数是相当新的功能(好吧,不是那么新,但仍然如此)。见stackoverflow.com/questions/531178/…。这可能是一个错误。
  • 好的。有谁知道如何向 Microsoft 的 F# 团队报告错误?
  • @jpierson - 实际上我认为github.com/Microsoft/visualfsharp/issues/new 是解决此类一般语言问题的正确位置。您的链接适用于在一个平台上出现但在另一个平台上不存在的问题。
  • @kvb - 好吧,我假设 VisualFSharp 主要只是 Microsoft 内部的问题,例如使用 Visual Studio 的工具,而不是像编译器错误这样更一般的问题。也许你是对的。

标签: f# discriminated-union


【解决方案1】:

这是一个协方差问题。 类型构造函数 Itemsseq&lt;int&gt; -&gt; Items,但被赋予了 List&lt;int&gt;,您必须显式向上转换,因为 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

【讨论】:

  • F# 在我给出的其他示例中确实进行了自动子类型转换。我想知道为什么这个案例的行为不同。
  • &gt;type Foo = Items of seq&lt;int&gt;;; &gt;Items;; val it : arg0:seq&lt;int&gt; -&gt; Foo = &lt;fun:clo@18-5&gt; let length (ints: int seq) = Seq.length ints &gt; let length (ints: int seq) = Items ints;; &gt; length;; val it : (seq&lt;int&gt; -&gt; Foo) = &lt;fun:it@20-3&gt; 相同的类型签名但仍然是同样的问题。我很确定这是一个错误。
  • @mydogisbox 同意。由于类型推断问题,他们可能有意保持构造函数严格。值得提出问题来确认。
  • 有扩展自动转换的工作,但目前不包括这种情况。这是来自 Don Syme 的评论:github.com/fsharp/fslang-suggestions/issues/…
【解决方案2】:

如果你把你的代码改成这样:

> 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>

问题变得更加明显。几乎相同的类型签名,但仍然是同样的问题。我很确定这是使用构造函数作为一等函数的错误。

【讨论】:

  • 好点。我将此报告为错误。让我们看看他们怎么说。
  • type Foo = Items of seq&lt;int&gt;;; let items = Items;; [1;2;3] |&gt; items;; 也可以,这IS是一回事。
【解决方案3】:

这更像是一个猜测而不是一个答案,但我怀疑这个问题可能与 C# 中的类似行为有关,因为构造函数不能有类型参数。默认情况下,我的理解是 F# 函数是完全通用的,只有通过类型注释和推理才能变得专门化。如果构造函数无法具有类型参数是 CLR 或 .NET 中普遍存在的问题,那么它可以解释为什么 F# 类型构造函数可能无法像函数那样在默认情况下遵循相同的泛型行为。

【讨论】:

  • 我上面的假设是正确的,那么在 C# 中经常使用的相同解决方法可能在 F# 中工作以在类型上创建一个静态工厂方法,然后使用必要的类型参数调用构造函数需要。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 2014-03-25
  • 1970-01-01
  • 1970-01-01
  • 2011-11-23
  • 1970-01-01
相关资源
最近更新 更多