【问题标题】:Why can't I create a generic function?为什么我不能创建一个通用函数?
【发布时间】:2017-03-04 20:22:22
【问题描述】:

在下面的代码中,编译器假定参数 r 是 Rec2 类型。由于类型 Rec1 具有函数定义中使用的所有字段,因此可以使用函数注释创建一个函数,其中 r 是 Rec1 类型。到目前为止,一切顺利。

但我希望 r 是另一种类型,比如 'a.不幸的是,我不知道 'a 是什么。所以我尝试创建一个泛型函数,其中 r 是泛型类型。下面的代码显示编译器不允许我这样做。

有没有办法创建这样一个通用函数?

type Rec1 = {A: int; B: string}
let r0 = {A = 0; B = "Hello"}
type Rec2 = {A: int; B: string; C: float}

let f2 (x, r) = {A = r.A; B = r.B; C = x}
// val f2 : x:float * r:Rec2 -> Rec2
let f1 (x, (r: Rec1)) = {A = r.A; B = r.B; C = x}
// val f1 : x:float * r:Rec1 -> Rec2
let g<'T> (x, (r: 'T)) = {A = r.A; B = r.B; C = x}
(* error FS0193: Type constraint mismatch. The type 
    'T    
is not compatible with type
    Rec2    
The type ''T' does not match the type 'Rec2' *)

【问题讨论】:

  • 你想解决什么问题?
  • 您的泛型类型不是任何类型,它应该有两个名为 A 和 B 的字段,因此您需要能够指定该限制。您可以使用静态约束以通用方式读取值,但不能以通用方式创建记录。
  • 因为简短的回答是否定的,这不是泛型的工作方式。很长的答案是肯定的,但你不想这样做。
  • @Gustavo - 我实际上有一个类型,其中包含两个名为 A 和 B 的字段,但我不知道它的名称。它是由 Csv 提供者创建的对象中的行的类型,我无法确定其签名以便将其插入类型注释中。
  • @Soldalma:提供的类型是静态的,因此它们可用于类型注释。这就是类型提供者的全部意义所在。查看您其他问题的答案。

标签: generics types f#


【解决方案1】:

cmets 显示您实际上正在使用 CSVProvider,这意味着您不需要这样做。你已经有静态类型了:

使用 FSharp.Data 文档中的示例 csv 文件:

日期、开盘价、最高价、最低价、收盘价、成交量、调整收盘价 2012-01-27,29.45,29.53,29.17,29.23,44187700,29.23 2012-01-26,29.61,29.70,29.40,29.50,49102800,29.50 2012-01-25,29.07,29.65,29.07,29.56,59231700,29.56 2012-01-24,29.47,29.57,29.18,29.34,51703300,29.34

只需使用Stocks.Row 作为类型:

type Stocks = CsvProvider<"test.csv">

type Rec2 = {Open: decimal; Close: decimal; Extra: string}

let openCloseWithExtra (stockRow : Stocks.Row) =
    {Open = stockRow.Open; Close = stockRow.Close; Extra = "extra"}

如果出于某种原因,您确实需要使用公开了两个属性的完全任意类型,您可以使用静态解析的类型参数来完成:

let inline anyOpenCloseWithExtra stockRow =
    let open' = ((^T) : (member Open : decimal) (stockRow))
    let close' = ((^T) : (member Close : decimal) (stockRow))
    {Open = open'; Close = close'; Extra = "extra"}

【讨论】:

  • 好的,谢谢。但是您是如何找到 Stocks.Row 的类型的?我的意思是,有没有我可以遵循的程序来找到 Stocks.Row 是类型?
  • @Soldalma 最明显的可能是查看Stocks.GetSample().Rows 的类型,你会看到它被列为seq&lt;CsvProvider&lt;...&gt;.Row&gt;,所以你知道每个元素都有CsvProvider&lt;...&gt;.Row 类型,即Stocks.Row 在这种情况下。
  • 我已经这样做了,但我没有弄清楚 CsvProvider&lt;...&gt; 的意思是 Stocks,即 CsvProvider 的名称。
猜你喜欢
  • 1970-01-01
  • 2016-04-05
  • 1970-01-01
  • 2019-12-05
  • 2015-10-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-30
  • 1970-01-01
相关资源
最近更新 更多