我正在学习F#和FSharp.Data library。我有一个任务,我需要阅读20个CSV文件。每个文件具有不同的列数,但记录具有相同的性质:键入日期字符串,其余所有列都是浮点数。在将结果保存到数据库之前,我需要对float格式数据列进行一些统计计算。虽然我得到了所有的管道逻辑工作:
解决方案远非可接受。我以为我可以创建一个通用的顶级函数作为循环遍历所有文件的驱动程序。然而,经过几天的尝试,我无处可去。
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">> =
....
的工作。
然后我尝试从
传递MSFTtype 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个不同文件的替代方法是什么?
答案 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/)