可以将类型提供程序作为参数传递给函数

时间:2014-02-04 11:54:51

标签: f# type-providers f#-data

我正在学习F#和FSharp.Data library。我有一个任务,我需要阅读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)
...

我试过了:

let mainfunc (typefile:string) (datafile:string) =
    let msft = CsvProvider<typefile>.Load(datafile)
    ....

这不起作用,因为CsvProvider抱怨typefile不是有效的常量表达式。我猜测类型提供者必须要求文件在编码时推断出列的类型,在使用相关信息调用mainfunc的代码之前,不能推迟类型推断。

然后我尝试将Type作为参数传递给mainfunc

既不是

let mainfunc (typeProvider:CsvProvider<"../docs/MSFT.csv">) =
    ....

也不是

let mainfunc<typeProvider:CsvProvider<"../docs/MSFT.csv">> =
    ....

的工作。

然后我尝试从

传递MSFT
type Stocks = CsvProvider<"../docs/MSFT.csv">
let msft = Stocks.Load("http://ichart.finance.yahoo.com/table.csv?s=MSFT")

进入mainFunc。根据intellisence,MSFT的类型为CsvProvider<...>,MSFT.Data的类型为seq<CsvProvider<...>>。我试图用这两个显式类型声明一个输入参数,但它们都不能通过编译。

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

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

1 个答案:

答案 0 :(得分:5)

这与Type annotation for using a F# TypeProvider type e.g. FSharp.Data.JsonProvider<...>.DomainTypes.Url

有关

尽管intellisense会向您显示CsvProvider<...>,但要在类型注释中引用msft类型,您必须使用Stocks,而使用msft.Data,而不是{{1} },你必须使用CsvProvider<...>.Row

如果你想做一些动态的事情,你可以使用Stocks.Row获取列名称,你可以使用msft.Headers获取列的类型(这是有效的,因为行被删除为元组运行时)

编辑:

如果格式不兼容,并且您处理的动态数据不符合常见格式,则可能需要使用Microsoft.FSharp.Reflection.FSharpType.GetTupleElements(typeof<Stocks.Row>)代替(http://fsharp.github.io/FSharp.Data/library/CsvFile.html),但是你会失去类型提供者的所有类型安全性。您也可以考虑使用Deedle(http://bluemountaincapital.github.io/Deedle/