F# 类型提供程序能否作为参数传递到函数中

F# 类型提供程序能否作为参数传递到函数中,f#,type-providers,f#-data,F#,Type Providers,F# Data,我正在学习F#和。我有一个任务,我需要读取20个CSV文件。每个文件具有不同的列数,但记录具有相同的性质:键入日期字符串,其余所有列都是浮点数。在将结果持久化到数据库之前,我需要对float格式的数据列进行一些统计计算。虽然我让所有的管道逻辑工作: 通过FSharp.Data CSV类型提供程序读取CSV 使用反射获取每个列字段的类型以及它们被输入到模式匹配中的标题名称,模式匹配决定了相关的计算逻辑 sqlbulkcopy(复制结果),我结束了20个函数(每个CSV文件1个) 这个解决方案远

我正在学习F#和。我有一个任务,我需要读取20个CSV文件。每个文件具有不同的列数,但记录具有相同的性质:键入日期字符串,其余所有列都是浮点数。在将结果持久化到数据库之前,我需要对float格式的数据列进行一些统计计算。虽然我让所有的管道逻辑工作:

  • 通过FSharp.Data CSV类型提供程序读取CSV
  • 使用反射获取每个列字段的类型以及它们被输入到模式匹配中的标题名称,模式匹配决定了相关的计算逻辑
  • sqlbulkcopy(复制结果),我结束了20个函数(每个CSV文件1个)
这个解决方案远远不能被接受。我想我可以创建一个通用的顶级函数作为驱动程序来循环遍历所有文件。然而,经过几天的努力,我还是一事无成

FSharp.Data CSV类型提供程序具有以下模式:

type Stocks = CsvProvider<"../docs/MSFT.csv">
let msft = Stocks.Load("http://ichart.finance.yahoo.com/table.csv?s=MSFT")
msft.Data |> Seq.map(fun row -> do something with row)
...
type Stocks=CsvProvider
设msft=Stocks.Load(“http://ichart.finance.yahoo.com/table.csv?s=MSFT")
msft.Data |>Seq.map(有趣的行->用行做点什么)
...
我试过:

let mainfunc (typefile:string) (datafile:string) =
    let msft = CsvProvider<typefile>.Load(datafile)
    ....
let mainfunc(类型文件:字符串)(数据文件:字符串)=
让msft=CsvProvider.Load(数据文件)
....
这不起作用,因为CsvProvider抱怨typefile不是有效的常量表达式。我猜类型提供程序在编码时必须需要该文件来推断列的类型,类型推断不能推迟到使用相关信息调用mainfunc的代码

然后,我尝试将该类型作为参数传递到mainfunc中

都不是

let mainfunc (typeProvider:CsvProvider<"../docs/MSFT.csv">) =
    ....
let mainfunc(类型提供程序:CsvProvider)=
....
也不是

let mainfunc=
....
成功了

然后,我试图通过MSFT从

type Stocks = CsvProvider<"../docs/MSFT.csv">
let msft = Stocks.Load("http://ichart.finance.yahoo.com/table.csv?s=MSFT")
type Stocks=CsvProvider
设msft=Stocks.Load(“http://ichart.finance.yahoo.com/table.csv?s=MSFT")
变成一个主要功能。根据intellisence,MSFT的类型为
CsvProvider
,而MSFT.Data的类型为
seq
。我试图声明一个显式类型为这两个的输入参数,但它们都不能通过编译

谁能帮我指一下正确的方向吗?我是不是错过了一些基本的东西?任何.net类型和类对象都可以在F#函数中用于显式指定参数类型,但是我可以从类型提供程序对类型执行相同的操作吗

如果上述问题的答案是否定的,那么有什么替代方法可以使逻辑通用化以处理20个文件甚至200个不同的文件

这与

即使intellisense向您显示
CsvProvider
,要在类型注释中引用
msft
类型,您必须使用
Stocks
,对于
msft.Data
,而不是
CsvProvider.Row
,您必须使用
Stocks.Row

如果要执行动态操作,可以使用
msft.Headers
获取列名称,还可以使用
Microsoft.FSharp.Reflection.FSharpType.GetTupleElements(typeof)
获取列类型(这是因为在运行时该行被擦除为元组)

编辑:


如果格式不兼容,并且您处理的动态数据不符合公共格式,那么您可能希望使用
CsvFile
代替(),但您将失去类型提供程序的所有类型安全性。您也可以考虑使用DeDLE()

谢谢您的回复。但在我的例子中,我有等价的类型:Stock1、Stock2、stock3。。。。股票20。我正在尝试使用一个函数,该函数可以(以其泛型形式)作为输入参数类型。作为过程的一部分,我使用反射函数将行分解为元组。然而,我最终用20个函数处理了20只股票。它们不是都有相似的格式吗?只需使用其中一个文件
type stock=CsvProvider
创建一个股票类型,然后调用
stock.Load(“stock1.csv”)
stock.Load(“stock2.csv”)
,等等……再次感谢您对Deedle和CsvFile解析的建议。我要试一试。虽然我的文件具有相似的性质,但它们有不同的列标题,甚至列数。我希望利用类型提供程序创建一个完全不知道文件格式的F#can,并纯粹基于列名和数据类型(使用反射)将数据持久化到数据库中。我想这种期望是不现实的。我希望从类型提供程序创建的类型被视为相同的“类型”。
type Stocks = CsvProvider<"../docs/MSFT.csv">
let msft = Stocks.Load("http://ichart.finance.yahoo.com/table.csv?s=MSFT")